Skip to content

Commit 7220760

Browse files
author
dcalixto
committed
update spec
1 parent 9ec7a88 commit 7220760

11 files changed

+140
-101
lines changed

config/database.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test:
2+
url: postgres://postgres:postgres@localhost:5432/punching_bag_test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# +micrate Up
2+
CREATE TABLE punches (
3+
id BIGSERIAL PRIMARY KEY,
4+
punchable_type VARCHAR(255),
5+
punchable_id BIGINT,
6+
hits INTEGER DEFAULT 1,
7+
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
8+
starts_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
9+
ends_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
10+
);
11+
12+
CREATE INDEX idx_punches_created_at ON punches(created_at);
13+
CREATE INDEX idx_punches_punchable ON punches(punchable_type, punchable_id);
14+
CREATE INDEX idx_punches_starts_at ON punches(starts_at);
15+
CREATE INDEX idx_punches_ends_at ON punches(ends_at);
16+
17+
# +micrate Down
18+
DROP TABLE IF EXISTS punches CASCADE;

db/migrations/20241217164800_create_punches.sql

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ CREATE TABLE punches (
99
ends_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
1010
);
1111

12-
CREATE INDEX punchable_index ON punches (punchable_type, punchable_id);
13-
CREATE INDEX created_at_index ON punches (created_at);
12+
CREATE INDEX idx_punches_created_at ON punches(created_at);
13+
CREATE INDEX idx_punches_punchable ON punches(punchable_type, punchable_id);
14+
CREATE INDEX idx_punches_starts_at ON punches(starts_at);
15+
CREATE INDEX idx_punches_ends_at ON punches(ends_at);
1416

1517
-- +micrate Down
16-
DROP TABLE IF EXISTS punches;
17-
DROP INDEX IF EXISTS punchable_index;
18-
DROP INDEX IF EXISTS created_at_index;
18+
DROP TABLE IF EXISTS punches CASCADE;

spec/db_setup_spec.cr

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
require "./spec_helper"
22

3-
require "./spec_helper"
4-
53
describe "DB Setup" do
64
describe "database connection" do
75
it "creates punches table with correct schema" do
@@ -23,6 +21,7 @@ describe "DB Setup" do
2321
end
2422
end
2523
end
24+
2625
describe "table schema" do
2726
it "has the expected columns" do
2827
DB.open(PunchingBag::Configuration.database_url) do |db|
@@ -41,21 +40,16 @@ describe "table schema" do
4140
end
4241
end
4342

44-
describe PunchingBag do
43+
describe PunchingBag::Configuration do
4544
before_each do
46-
File.delete("./punching_bag.db") if File.exists?("./punching_bag.db")
47-
end
48-
49-
after_each do
50-
File.delete("./punching_bag.db") if File.exists?("./punching_bag.db")
45+
PunchingBag.configure do |config|
46+
config.database_url = "postgres://postgres:postgres@localhost:5432/punching_bag_test"
47+
end
5148
end
5249

53-
describe ".configure" do
54-
it "allows setting custom database url" do
55-
PunchingBag.configure do |config|
56-
config.database_url = "postgres://localhost/punching_bag_test"
57-
end
58-
PunchingBag::Configuration.database_url.should eq("postgres://localhost/punching_bag_test")
50+
it "connects to database" do
51+
DB.open(PunchingBag::Configuration.database_url) do |db|
52+
# Your test code here
5953
end
6054
end
6155
end

spec/punching_bag_spec.cr

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
require "./spec_helper"
2+
require "./test_helper"
23

34
describe PunchingBag do
4-
it "tracks and retrieves hits correctly" do
5+
before_each do
6+
TestHelper.setup_test_db
7+
end
8+
9+
it "tracks hits" do
510
bag = PunchingBag::Tracker.new(TestHelper.database)
611
bag.clear
712

@@ -76,16 +81,17 @@ describe "Database Setup" do
7681
end
7782
end
7883

79-
it "creates required indexes" do
80-
db = TestHelper.database
81-
results = db.query_all(<<-SQL, as: {name: String})
82-
SELECT indexname as name
83-
FROM pg_indexes
84-
WHERE tablename = 'punches'
85-
AND indexname != 'punches_pkey';
86-
SQL
87-
88-
results.any? { |r| r[:name] == "punchable_index" }.should be_true
89-
results.any? { |r| r[:name] == "idx_punches_created_at" }.should be_true
84+
describe "Database Setup" do
85+
it "creates required indexes" do
86+
results = [] of NamedTuple(name: String)
87+
DB.open(DB_URL) do |db|
88+
db.query "SELECT indexname as name FROM pg_indexes WHERE tablename = 'punches'" do |rs|
89+
rs.each do
90+
results << {name: rs.read(String)}
91+
end
92+
end
93+
end
94+
results.any? { |r| r[:name] == "idx_punches_created_at" }.should be_true
95+
end
9096
end
9197
end

spec/spec_helper.cr

+20-25
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
require "spec"
2+
require "webmock"
23
require "../src/punching_bag"
3-
require "./test_helper"
4+
require "db"
5+
require "pg"
6+
require "micrate"
47

5-
PunchingBag.configure do |config|
6-
config.database_url = "postgres://postgres:postgres@localhost:5432/punching_bag_test"
7-
end
8+
DB_URL = "postgres://postgres:postgres@localhost:5432/punching_bag_test"
89

910
Spec.before_each do
10-
TestHelper.database.exec "DROP TABLE IF EXISTS punches"
11-
12-
TestHelper.database.exec <<-SQL
13-
CREATE TABLE punches (
14-
id BIGSERIAL PRIMARY KEY,
15-
punchable_type VARCHAR(255),
16-
punchable_id BIGINT,
17-
hits INTEGER DEFAULT 1,
18-
created_at TIMESTAMP WITH TIME ZONE,
19-
starts_at TIMESTAMP WITH TIME ZONE,
20-
ends_at TIMESTAMP WITH TIME ZONE
21-
)
22-
SQL
11+
WebMock.reset
2312

24-
TestHelper.database.exec <<-SQL
25-
CREATE INDEX punchable_index ON punches (punchable_type, punchable_id)
26-
SQL
13+
# Clean database first
14+
DB.open(DB_URL) do |db|
15+
db.exec "DROP TABLE IF EXISTS punches"
16+
db.exec "DROP TABLE IF EXISTS micrate_db_version"
17+
end
2718

28-
TestHelper.database.exec <<-SQL
29-
CREATE INDEX idx_punches_created_at ON punches (created_at)
30-
SQL
19+
# Run migrations
20+
Micrate::DB.connection_url = DB_URL
21+
Micrate::Cli.run_up
3122
end
32-
Spec.after_suite do
33-
TestHelper.database.close
23+
24+
PunchingBag.configure do |config|
25+
config.database_url = DB_URL
26+
config.db = DB.open(DB_URL)
3427
end
28+
29+
# No need to run migrations down since we're dropping tables in before_each

spec/test_helper.cr

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
module TestHelper
2-
@@db : DB::Database?
1+
require "./spec_helper"
32

3+
module TestHelper
44
def self.database
5-
@@db ||= DB.open(PunchingBag::Configuration.database_url)
5+
DB.open("postgres://postgres:postgres@localhost:5432/punching_bag_test")
6+
end
7+
8+
def self.setup_test_db
9+
db = database
10+
db.exec "DROP TABLE IF EXISTS hits"
11+
db.exec "CREATE TABLE hits (id SERIAL PRIMARY KEY, punchable_type VARCHAR, punchable_id INTEGER, hits INTEGER DEFAULT 0, created_at TIMESTAMP, updated_at TIMESTAMP)"
612
end
713
end

src/punching_bag.cr

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
require "db"
22
require "pg"
3+
require "./punching_bag/version"
34
require "./punching_bag/configuration"
5+
require "./punching_bag/tracker"
46
require "./punching_bag/cli"
57

68
module PunchingBag
7-
@@db : DB::Database? = nil
8-
9-
def self.db
10-
@@db.not_nil!
11-
end
12-
13-
def self.db=(database : DB::Database)
14-
@@db = database
9+
def self.configure
10+
yield Configuration.config
1511
end
1612

1713
class Tracker

src/punching_bag/configuration.cr

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
module PunchingBag
22
class Configuration
3-
@@db : DB::Database? = nil
3+
property database_url : String = "postgres://postgres:postgres@localhost:5432/punching_bag_test"
4+
property db : DB::Database?
45

5-
def self.db : DB::Database
6-
@@db ||= DB.open(ENV["DATABASE_URL"])
6+
@@config = Configuration.new
7+
8+
def self.configure
9+
yield @@config
710
end
811

9-
def self.db=(database : DB::Database)
10-
@@db = database
12+
def self.config
13+
@@config
1114
end
12-
end
1315

14-
def self.configure
15-
yield Configuration
16-
end
16+
def self.database_url
17+
@@config.database_url
18+
end
1719

18-
def self.db
19-
Configuration.db
20+
def self.db
21+
@@config.db
22+
end
2023
end
2124
end

src/punching_bag/tracker.cr

+39-23
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
1-
def setup_table
2-
drop_table
3-
create_table
4-
create_indexes
5-
end
6-
7-
private def drop_table
8-
@db.exec("DROP TABLE IF EXISTS punches CASCADE")
9-
end
1+
module PunchingBag
2+
class Tracker
3+
def initialize(@db : DB::Database)
4+
end
105

11-
private def create_table
12-
@db.exec <<-SQL
13-
CREATE TABLE punches (
14-
id BIGSERIAL PRIMARY KEY,
15-
punchable_type VARCHAR(255),
16-
punchable_id BIGINT,
17-
hits INTEGER DEFAULT 1,
18-
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
19-
starts_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
20-
ends_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
6+
def hit(punchable_type : String, punchable_id : Int32)
7+
@db.exec(
8+
"INSERT INTO hits (punchable_type, punchable_id, hits, created_at, updated_at)
9+
VALUES ($1, $2, 1, NOW(), NOW())
10+
ON CONFLICT (punchable_type, punchable_id)
11+
DO UPDATE SET hits = hits.hits + 1, updated_at = NOW()",
12+
punchable_type, punchable_id
2113
)
22-
SQL
23-
end
14+
end
15+
16+
def setup_table
17+
drop_table
18+
create_table
19+
create_indexes
20+
end
21+
22+
private def drop_table
23+
@db.exec("DROP TABLE IF EXISTS hits CASCADE")
24+
end
25+
26+
private def create_table
27+
@db.exec <<-SQL
28+
CREATE TABLE hits (
29+
id BIGSERIAL PRIMARY KEY,
30+
punchable_type VARCHAR(255),
31+
punchable_id BIGINT,
32+
hits INTEGER DEFAULT 1,
33+
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
34+
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
35+
)
36+
SQL
37+
end
2438

25-
private def create_indexes
26-
@db.exec("CREATE INDEX IF NOT EXISTS idx_punches_punchable ON punches(punchable_type, punchable_id)")
39+
private def create_indexes
40+
@db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_hits_punchable ON hits(punchable_type, punchable_id)")
41+
end
42+
end
2743
end

src/punching_bag/version.cr

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module PunchingBag
2+
VERSION = "0.1.0"
3+
end

0 commit comments

Comments
 (0)