hummingbird 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/.gitignore +16 -0
  2. data/.travis.yml +4 -0
  3. data/CONTRIBUTING.md +7 -0
  4. data/Gemfile +15 -0
  5. data/Guardfile +9 -0
  6. data/LICENSE +20 -0
  7. data/README.md +134 -0
  8. data/Rakefile +10 -0
  9. data/hummingbird.gemspec +31 -0
  10. data/lib/hummingbird/configuration.rb +35 -0
  11. data/lib/hummingbird/database.rb +31 -0
  12. data/lib/hummingbird/plan.rb +75 -0
  13. data/lib/hummingbird/plan_error.rb +11 -0
  14. data/lib/hummingbird/version.rb +3 -0
  15. data/lib/hummingbird.rb +7 -0
  16. data/test/fixtures/basic_config.yml +6 -0
  17. data/test/fixtures/no_basedir_config.yml +3 -0
  18. data/test/fixtures/no_basedir_user_config.yml +3 -0
  19. data/test/fixtures/no_connection_string_config.yml +5 -0
  20. data/test/fixtures/no_migrations_dir_config.yml +3 -0
  21. data/test/fixtures/no_migrations_dir_user_config.yml +3 -0
  22. data/test/fixtures/no_migrations_table_config.yml +4 -0
  23. data/test/fixtures/no_planfile_config.yml +3 -0
  24. data/test/fixtures/no_planfile_user_config.yml +3 -0
  25. data/test/fixtures/plan/basic.plan +4 -0
  26. data/test/fixtures/sql/migrations/basic/file1.sql +1 -0
  27. data/test/fixtures/sql/migrations/basic/file2.sql +1 -0
  28. data/test/fixtures/sql/migrations/basic/file3.sql +1 -0
  29. data/test/fixtures/sql/migrations/basic/file4.sql +1 -0
  30. data/test/fixtures/sql/migrations_table.sql +4 -0
  31. data/test/fixtures/user_config.yml +4 -0
  32. data/test/lib/hummingbird/configuration_test.rb +153 -0
  33. data/test/lib/hummingbird/database_test.rb +100 -0
  34. data/test/lib/hummingbird/plan_test.rb +230 -0
  35. data/test/lib/hummingbird/version_test.rb +7 -0
  36. data/test/test_helper.rb +66 -0
  37. data/test/test_helper_test.rb +41 -0
  38. metadata +237 -0
@@ -0,0 +1,3 @@
1
+ ---
2
+ planfile: 'user-application.plan'
3
+ migrations_dir: 'user-migrations-dir'
@@ -0,0 +1,5 @@
1
+ ---
2
+ basedir: 'sql'
3
+ planfile: 'application.plan'
4
+ migrations_dir: 'migrations-dir'
5
+ migrations_table: 'application_migrations'
@@ -0,0 +1,3 @@
1
+ ---
2
+ basedir: 'sql'
3
+ planfile: 'application.plan'
@@ -0,0 +1,3 @@
1
+ ---
2
+ basedir: 'user-sql'
3
+ planfile: 'user-application.plan'
@@ -0,0 +1,4 @@
1
+ ---
2
+ basedir: 'sql'
3
+ planfile: 'application.plan'
4
+ migrations_dir: 'migrations-dir'
@@ -0,0 +1,3 @@
1
+ ---
2
+ basedir: 'sql'
3
+ migrations_dir: 'migrations'
@@ -0,0 +1,3 @@
1
+ ---
2
+ basedir: 'user-sql'
3
+ migrations_dir: 'user-migrations-dir'
@@ -0,0 +1,4 @@
1
+ file1.sql
2
+ file2.sql
3
+ file3.sql
4
+ file4.sql
@@ -0,0 +1 @@
1
+ CREATE TABLE table1 (name text);
@@ -0,0 +1 @@
1
+ CREATE TABLE table2 (name text);
@@ -0,0 +1 @@
1
+ CREATE TABLE table3 (name text);
@@ -0,0 +1 @@
1
+ CREATE TABLE table4 (name text);
@@ -0,0 +1,4 @@
1
+ CREATE TABLE hummingbird_migrations (
2
+ migration_name text,
3
+ run_on integer
4
+ );
@@ -0,0 +1,4 @@
1
+ ---
2
+ basedir: 'user-sql'
3
+ planfile: 'user-application.plan'
4
+ migrations_dir: 'user-migrations-dir'
@@ -0,0 +1,153 @@
1
+ require 'test_helper'
2
+
3
+ describe Hummingbird::Configuration do
4
+ before do
5
+ @tempdir = tempdir
6
+ end
7
+
8
+ it 'defines the CONFIG_FILE basename constant' do
9
+ assert_equal 'hummingbird.yml', Hummingbird::Configuration::CONFIG_FILE
10
+ end
11
+
12
+ it 'defines the USER_CONFIG_FILE basename constant' do
13
+ assert_equal '.hummingbird.yml', Hummingbird::Configuration::USER_CONFIG_FILE
14
+ end
15
+
16
+ it 'loads the hummingbird.yml file from the specified config_dir' do
17
+ copy_fixture_to(
18
+ 'basic_config.yml',
19
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
20
+ )
21
+
22
+ config = Hummingbird::Configuration.new(@tempdir)
23
+
24
+ assert_equal 'sql', config.basedir
25
+ assert_equal _with_basedir(config, 'application.plan'), config.planfile
26
+ assert_equal _with_basedir(config, 'migrations-dir'), config.migrations_dir
27
+ assert_equal :application_migrations, config.migrations_table
28
+ assert_equal 'sequel connection string', config.connection_string
29
+ end
30
+
31
+ it "defaults #basedir to be '.'" do
32
+ copy_fixture_to(
33
+ 'no_basedir_config.yml',
34
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
35
+ )
36
+
37
+ config = Hummingbird::Configuration.new(@tempdir)
38
+
39
+ assert_equal '.', config.basedir
40
+ end
41
+
42
+ it "defaults #planfile to be basedir + 'hummingbird.plan'" do
43
+ copy_fixture_to(
44
+ 'no_planfile_config.yml',
45
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
46
+ )
47
+
48
+ config = Hummingbird::Configuration.new(@tempdir)
49
+
50
+ assert_equal _with_basedir(config,'hummingbird.plan'), config.planfile
51
+ end
52
+
53
+ it "defaults #migrations_dir to be basedir + 'migrations'" do
54
+ copy_fixture_to(
55
+ 'no_migrations_dir_config.yml',
56
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
57
+ )
58
+
59
+ config = Hummingbird::Configuration.new(@tempdir)
60
+
61
+ assert_equal _with_basedir(config,'migrations'), config.migrations_dir
62
+ end
63
+
64
+ it 'defaults #migrations_table to be :hummingbird_migrations' do
65
+ copy_fixture_to(
66
+ 'no_migrations_table_config.yml',
67
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
68
+ )
69
+
70
+ config = Hummingbird::Configuration.new(@tempdir)
71
+
72
+ assert_equal :hummingbird_migrations, config.migrations_table
73
+ end
74
+
75
+ it "does not have a default #connection_string" do
76
+ copy_fixture_to(
77
+ 'no_connection_string_config.yml',
78
+ File.join(@tempdir, Hummingbird::Configuration::CONFIG_FILE)
79
+ )
80
+
81
+ config = Hummingbird::Configuration.new(@tempdir)
82
+
83
+ assert_equal nil, config.connection_string
84
+ end
85
+
86
+ it "prefers the user's configuration file if one is present" do
87
+ [['basic_config.yml', Hummingbird::Configuration::CONFIG_FILE],
88
+ ['user_config.yml', Hummingbird::Configuration::USER_CONFIG_FILE]].each do |s,d|
89
+ copy_fixture_to(s, File.join(@tempdir, d))
90
+ end
91
+
92
+ config = nil
93
+ FileUtils.stub :pwd, @tempdir do
94
+ config = Hummingbird::Configuration.new(@tempdir)
95
+ end
96
+
97
+ assert_equal 'user-sql', config.basedir
98
+ assert_equal _with_basedir(config,'user-application.plan'), config.planfile
99
+ assert_equal _with_basedir(config,'user-migrations-dir'), config.migrations_dir
100
+ end
101
+
102
+ it "uses non-user basedir if not present for user" do
103
+ [['basic_config.yml', Hummingbird::Configuration::CONFIG_FILE],
104
+ ['no_basedir_user_config.yml', Hummingbird::Configuration::USER_CONFIG_FILE]].each do |s,d|
105
+ copy_fixture_to(s, File.join(@tempdir, d))
106
+ end
107
+
108
+ config = nil
109
+ FileUtils.stub :pwd, @tempdir do
110
+ config = Hummingbird::Configuration.new(@tempdir)
111
+ end
112
+
113
+ assert_equal 'sql', config.basedir
114
+ assert_equal _with_basedir(config, 'user-application.plan'), config.planfile
115
+ assert_equal _with_basedir(config, 'user-migrations-dir'), config.migrations_dir
116
+ end
117
+
118
+ it "uses non-user planfile if not present for user" do
119
+ [['basic_config.yml', Hummingbird::Configuration::CONFIG_FILE],
120
+ ['no_planfile_user_config.yml', Hummingbird::Configuration::USER_CONFIG_FILE]].each do |s,d|
121
+ copy_fixture_to(s, File.join(@tempdir, d))
122
+ end
123
+
124
+ config = nil
125
+ FileUtils.stub :pwd, @tempdir do
126
+ config = Hummingbird::Configuration.new(@tempdir)
127
+ end
128
+
129
+ assert_equal 'user-sql', config.basedir
130
+ assert_equal _with_basedir(config, 'application.plan'), config.planfile
131
+ assert_equal _with_basedir(config, 'user-migrations-dir'), config.migrations_dir
132
+ end
133
+
134
+ it "uses non-user migrations_dir if not present for user" do
135
+ [['basic_config.yml', Hummingbird::Configuration::CONFIG_FILE],
136
+ ['no_migrations_dir_user_config.yml', Hummingbird::Configuration::USER_CONFIG_FILE]].each do |s,d|
137
+ copy_fixture_to(s, File.join(@tempdir, d))
138
+ end
139
+
140
+ config = nil
141
+ FileUtils.stub :pwd, @tempdir do
142
+ config = Hummingbird::Configuration.new(@tempdir)
143
+ end
144
+
145
+ assert_equal 'user-sql', config.basedir
146
+ assert_equal _with_basedir(config, 'user-application.plan'), config.planfile
147
+ assert_equal _with_basedir(config, 'migrations-dir'), config.migrations_dir
148
+ end
149
+
150
+ def _with_basedir(config,path)
151
+ File.expand_path(File.join(config.basedir,path))
152
+ end
153
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+ require 'sqlite3'
3
+
4
+ describe Hummingbird::Database do
5
+ describe 'with an sqlite3 database' do
6
+ it 'reports the database as uninitialized if the migrations table is not found' do
7
+ sqlite_db = tempfile
8
+ sqlite_db.close
9
+
10
+ db = Hummingbird::Database.new("sqlite://#{sqlite_db.path}", :hummingbird_migrations)
11
+
12
+ assert_equal false, db.initialized?, 'DB should not be initialized'
13
+ end
14
+
15
+ it 'reports the database as initialized if the migrations table exists' do
16
+ sqlite_db_path = tempfile.path
17
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
18
+
19
+ sqlite_db.execute "create table hummingbird_migrations (migration_name text);"
20
+
21
+ db = Hummingbird::Database.new("sqlite://#{sqlite_db_path}", :hummingbird_migrations)
22
+
23
+ assert_equal true, db.initialized?, 'DB should be initialized'
24
+ end
25
+
26
+ it 'returns an empty list of already run migrations if the database has not already been initialized' do
27
+ sqlite_db_path = tempfile.path
28
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
29
+
30
+ db = Hummingbird::Database.new("sqlite://#{sqlite_db_path}", :hummingbird_migrations)
31
+
32
+ assert_set_equal [], db.already_run_migrations
33
+ end
34
+
35
+ it 'returns a list of the migrations that have already been run, in ascending run order of run date' do
36
+ sqlite_db_path = tempfile.path
37
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
38
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
39
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
40
+ [ ['third_migration.sql', DateTime.new(2012,10,11,12,0,0,'-7').strftime('%s')],
41
+ ['first_migration.sql', DateTime.new(2012,10, 1,13,0,0,'-7').strftime('%s')],
42
+ ['second_migration.sql', DateTime.new(2012,10, 8, 8,0,0,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
43
+
44
+ db = Hummingbird::Database.new("sqlite://#{sqlite_db_path}", :hummingbird_migrations)
45
+
46
+ assert_equal(
47
+ [ { migration_name: 'first_migration.sql', run_on: DateTime.new(2012,10, 1,13,0,0,'-7').strftime('%s').to_i },
48
+ { migration_name: 'second_migration.sql', run_on: DateTime.new(2012,10, 8, 8,0,0,'-7').strftime('%s').to_i },
49
+ { migration_name: 'third_migration.sql', run_on: DateTime.new(2012,10,11,12,0,0,'-7').strftime('%s').to_i }
50
+ ],
51
+ db.already_run_migrations
52
+ )
53
+ end
54
+
55
+ it 'records and runs migrations specified via #run_migration' do
56
+ sqlite_db_path = tempfile.path
57
+ connect_string = "sqlite://#{sqlite_db_path}"
58
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
59
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
60
+
61
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
62
+
63
+ migration_time = DateTime.new(2012,10,15,14,03,40,'-7')
64
+ DateTime.stub :now, migration_time do
65
+ db.run_migration('test_migration.sql', 'CREATE TABLE test_table (col1 text);')
66
+ end
67
+
68
+ assert_equal(
69
+ [{migration_name: 'test_migration.sql', run_on: migration_time.strftime('%s').to_i}],
70
+ db.already_run_migrations
71
+ )
72
+
73
+ assert_includes Sequel.connect(connect_string).tables, :test_table
74
+ end
75
+
76
+ it 'allows bootstrapping the DB via #run_migration' do
77
+ sqlite_db_path = tempfile.path
78
+ connect_string = "sqlite://#{sqlite_db_path}"
79
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
80
+
81
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
82
+
83
+ seconds = 40
84
+ DateTime.stub :now, lambda { DateTime.new(2012,10,15,14,03,seconds+=1,'-7') } do
85
+ db.run_migration('bootstrap_hummingbird.sql', read_fixture('sql', 'migrations_table.sql'))
86
+ db.run_migration('test_migration.sql', 'CREATE TABLE test_table (col1 text);')
87
+ end
88
+
89
+ assert_equal(
90
+ [
91
+ {migration_name: 'bootstrap_hummingbird.sql', run_on: DateTime.new(2012,10,15,14,03,41,'-7').strftime('%s').to_i},
92
+ {migration_name: 'test_migration.sql', run_on: DateTime.new(2012,10,15,14,03,42,'-7').strftime('%s').to_i}
93
+ ],
94
+ db.already_run_migrations
95
+ )
96
+
97
+ assert_includes Sequel.connect(connect_string).tables, :test_table
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,230 @@
1
+ require 'test_helper'
2
+ require 'sqlite3'
3
+
4
+ describe Hummingbird::Plan do
5
+ it 'reads the planned file list from the planfile' do
6
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), tempdir)
7
+
8
+ assert_equal(
9
+ ['file1.sql','file2.sql','file3.sql','file4.sql'],
10
+ plan.planned_files
11
+ )
12
+ end
13
+
14
+ it 'gets the list of migration files from examining config.migration_dir' do
15
+ migration_dir = tempdir
16
+ migration_files = ['migration1.sql','migration2.sql','migration3.sql']
17
+ FileUtils.touch migration_files.map {|f| File.join(migration_dir,f)}
18
+
19
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), migration_dir)
20
+
21
+ assert_equal(
22
+ migration_files.sort,
23
+ plan.migration_files.sort
24
+ )
25
+ end
26
+
27
+ it 'recurses into config.migration_dir to get the list of migration files' do
28
+ migration_dir = tempdir
29
+ migration_files = [['a','b','migration1.sql'],['a','migration2.sql'],['migration3.sql']].map {|f| File.join(*f)}
30
+ FileUtils.mkdir_p(File.join(migration_dir, 'a', 'b'))
31
+ FileUtils.touch migration_files.map {|f| File.join(migration_dir, f)}
32
+
33
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), migration_dir)
34
+
35
+ assert_equal(
36
+ migration_files.sort,
37
+ plan.migration_files.sort
38
+ )
39
+ end
40
+
41
+ it 'returns the list of files missing from the plan' do
42
+ migration_dir = tempdir
43
+ migration_files = (0..6).map {|n| "file#{n}.sql"}
44
+ FileUtils.touch migration_files.map {|f| File.join(migration_dir,f)}
45
+
46
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), migration_dir)
47
+
48
+ assert_set_equal [migration_files[0],*migration_files[-2,2]], plan.files_missing_from_plan, 'Wrong files missing from plan'
49
+ assert_set_equal [], plan.files_missing_from_migration_dir, 'Wrong files missing from migration_dir'
50
+ end
51
+
52
+ it 'returns the list of extra files in the plan' do
53
+ migration_dir = tempdir
54
+ migration_files = (2..3).map {|n| "file#{n}.sql"}
55
+ FileUtils.touch migration_files.map {|f| File.join(migration_dir,f)}
56
+
57
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), migration_dir)
58
+
59
+ assert_set_equal ['file1.sql','file4.sql'], plan.files_missing_from_migration_dir, 'Wrong files missing from migration_dir'
60
+ assert_set_equal [], plan.files_missing_from_plan, 'Wrong files missing from plan'
61
+ end
62
+
63
+ it 'reports no files missing when plan, and migration_dir are in sync' do
64
+ migration_dir = tempdir
65
+ migration_files = (1..4).map {|n| "file#{n}.sql"}
66
+ FileUtils.touch migration_files.map {|f| File.join(migration_dir,f)}
67
+
68
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), migration_dir)
69
+
70
+ assert_set_equal [], plan.files_missing_from_migration_dir, 'Wrong files missing from migration_dir'
71
+ assert_set_equal [], plan.files_missing_from_plan, 'Wrong files missing from plan'
72
+ end
73
+
74
+ describe '#to_be_run_migration_file_names' do
75
+ it 'returns all planned files when the db is uninitialized' do
76
+ sqlite_db_path = tempfile.path
77
+
78
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
79
+ db = Hummingbird::Database.new("sqlite://#{sqlite_db_path}", :hummingbird_migrations)
80
+
81
+ assert_equal(
82
+ ['file1.sql','file2.sql','file3.sql','file4.sql'],
83
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
84
+ )
85
+ end
86
+
87
+ it 'returns all planned files when no migrations have been run' do
88
+ sqlite_db_path = tempfile.path
89
+ connect_string = "sqlite://#{sqlite_db_path}"
90
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
91
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
92
+
93
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
94
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
95
+
96
+ assert_equal(
97
+ ['file1.sql','file2.sql','file3.sql','file4.sql'],
98
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
99
+ )
100
+ end
101
+
102
+ it 'returns all planned files after the last run migration when plan and DB are in sync to that point' do
103
+ sqlite_db_path = tempfile.path
104
+ connect_string = "sqlite://#{sqlite_db_path}"
105
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
106
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
107
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
108
+ [ ['file1.sql', DateTime.new(2012,10, 1,12,0,0,'-7').strftime('%s')],
109
+ ['file2.sql', DateTime.new(2012,10,11,13,0,0,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
110
+
111
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
112
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
113
+
114
+ assert_equal(
115
+ ['file3.sql','file4.sql'],
116
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
117
+ )
118
+ end
119
+
120
+ it 'raises when a yet-to-be-run planned file is before a recorded migration' do
121
+ sqlite_db_path = tempfile.path
122
+ connect_string = "sqlite://#{sqlite_db_path}"
123
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
124
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
125
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
126
+ file3_run_on = DateTime.new(2012,10,11,13,0,0,'-7')
127
+ [ ['file1.sql', DateTime.new(2012,10, 1,12,0,0,'-7').strftime('%s')],
128
+ ['file3.sql', file3_run_on.strftime('%s')]].each {|data| stmt.execute(*data)}
129
+
130
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
131
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
132
+
133
+ e = assert_raises Hummingbird::PlanError do
134
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
135
+ end
136
+
137
+ assert_equal "Plan has 'file2.sql' before 'file3.sql' which was run on #{file3_run_on.new_offset(0)}", e.message
138
+ end
139
+
140
+ it 'raises when the plan file is not in the same order as the recorded migrations' do
141
+ sqlite_db_path = tempfile.path
142
+ connect_string = "sqlite://#{sqlite_db_path}"
143
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
144
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
145
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
146
+ file4_run_on = DateTime.new(2012,10,2,13,1,1,'-7')
147
+ [ ['file1.sql', DateTime.new(2012,10,1,12,0,0,'-7').strftime('%s')],
148
+ ['file4.sql', file4_run_on.strftime('%s')],
149
+ ['file3.sql', DateTime.new(2012,10,3,14,2,2,'-7').strftime('%s')],
150
+ ['file2.sql', DateTime.new(2012,10,4,15,3,3,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
151
+
152
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
153
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
154
+
155
+ e = assert_raises Hummingbird::PlanError do
156
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
157
+ end
158
+
159
+ assert_equal "Plan has 'file2.sql' before 'file4.sql' which was run on #{file4_run_on.new_offset(0)}", e.message
160
+ end
161
+
162
+ it 'raises when a recorded migration is missing from the plan' do
163
+ sqlite_db_path = tempfile.path
164
+ connect_string = "sqlite://#{sqlite_db_path}"
165
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
166
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
167
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
168
+ [ ['file1.sql', DateTime.new(2012,10,1,12,0,0,'-7').strftime('%s')],
169
+ ['file2.sql', DateTime.new(2012,10,2,13,1,1,'-7').strftime('%s')],
170
+ ['file3.sql', DateTime.new(2012,10,3,14,2,2,'-7').strftime('%s')],
171
+ ['file4.sql', DateTime.new(2012,10,4,15,3,3,'-7').strftime('%s')],
172
+ ['file5.sql', DateTime.new(2012,10,5,16,4,4,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
173
+
174
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
175
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
176
+
177
+ e = assert_raises Hummingbird::PlanError do
178
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
179
+ end
180
+
181
+ assert_equal "Plan is missing the following already run migrations: file5.sql", e.message
182
+ end
183
+
184
+ it 'does not modify #planned_files' do
185
+ sqlite_db_path = tempfile.path
186
+ connect_string = "sqlite://#{sqlite_db_path}"
187
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
188
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
189
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
190
+ [ ['file1.sql', DateTime.new(2012,10, 1,12,0,0,'-7').strftime('%s')],
191
+ ['file2.sql', DateTime.new(2012,10,11,13,0,0,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
192
+
193
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
194
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
195
+
196
+ assert_equal ['file1.sql','file2.sql','file3.sql','file4.sql'], plan.planned_files
197
+
198
+ plan.to_be_run_migration_file_names(db.already_run_migrations)
199
+
200
+ assert_equal ['file1.sql','file2.sql','file3.sql','file4.sql'], plan.planned_files
201
+ end
202
+ end
203
+
204
+ describe '#migrations_to_be_run' do
205
+ it 'attaches the migration file contents to the #to_be_run_migration_file_names list' do
206
+ sqlite_db_path = tempfile.path
207
+ connect_string = "sqlite://#{sqlite_db_path}"
208
+ sqlite_db = SQLite3::Database.new(sqlite_db_path)
209
+ sqlite_db.execute read_fixture('sql', 'migrations_table.sql')
210
+ stmt = sqlite_db.prepare('INSERT INTO hummingbird_migrations (migration_name, run_on) VALUES (?,?);')
211
+ [ ['file1.sql', DateTime.new(2012,10, 1,12,0,0,'-7').strftime('%s')],
212
+ ['file2.sql', DateTime.new(2012,10,11,13,0,0,'-7').strftime('%s')]].each {|data| stmt.execute(*data)}
213
+
214
+ plan = Hummingbird::Plan.new(path_to_fixture('plan','basic.plan'), path_to_fixture('sql','migrations','basic'))
215
+ db = Hummingbird::Database.new(connect_string, :hummingbird_migrations)
216
+
217
+ migrations = plan.stub :to_be_run_migration_file_names, ['file3.sql','file4.sql'] do
218
+ plan.migrations_to_be_run(db.already_run_migrations)
219
+ end
220
+
221
+ assert_equal(
222
+ [
223
+ {migration_name: 'file3.sql', sql: "CREATE TABLE table3 (name text);\n"},
224
+ {migration_name: 'file4.sql', sql: "CREATE TABLE table4 (name text);\n"},
225
+ ],
226
+ migrations
227
+ )
228
+ end
229
+ end
230
+ end