hummingbird 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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