mince_migrator 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +20 -58
- data/bin/mince_migrator +125 -0
- data/lib/mince_migrator/cli_helper.rb +72 -0
- data/lib/mince_migrator/config.rb +30 -0
- data/lib/mince_migrator/creator.rb +48 -0
- data/lib/mince_migrator/deleter.rb +42 -0
- data/lib/mince_migrator/list.rb +46 -0
- data/lib/mince_migrator/list_report.rb +67 -0
- data/lib/mince_migrator/migration.rb +66 -0
- data/lib/mince_migrator/migrations/file.rb +74 -0
- data/lib/mince_migrator/migrations/loader.rb +52 -0
- data/lib/mince_migrator/migrations/name.rb +48 -0
- data/lib/mince_migrator/migrations/runner.rb +39 -0
- data/lib/mince_migrator/migrations/runner_validator.rb +47 -0
- data/lib/mince_migrator/migrations/template.mustache +24 -0
- data/lib/mince_migrator/migrations/template.rb +16 -0
- data/lib/mince_migrator/migrations/versioned_file.rb +38 -0
- data/lib/mince_migrator/ran_migration.rb +27 -0
- data/lib/mince_migrator/reverter.rb +57 -0
- data/lib/mince_migrator/status_report.rb +41 -0
- data/lib/mince_migrator/version.rb +18 -1
- data/lib/mince_migrator.rb +5 -4
- data/spec/integration/create_a_migration_spec.rb +57 -0
- data/spec/integration/deleting_a_migration_spec.rb +40 -0
- data/spec/integration/list_all_migrations_spec.rb +57 -0
- data/spec/integration/reverting_a_migration_spec.rb +59 -0
- data/spec/integration/running_a_migration_spec.rb +66 -0
- data/spec/integration_helper.rb +17 -0
- data/spec/support/db/a_second_migration.rb +24 -0
- data/spec/support/db/a_second_migration_2.rb +24 -0
- data/spec/support/db/create_seeded_admin_users.rb +24 -0
- data/spec/support/db/first_migration.rb +24 -0
- data/spec/support/db/first_migration_2.rb +24 -0
- data/spec/support/db/first_migration_3.rb +24 -0
- data/spec/support/db/first_migration_4.rb +24 -0
- data/spec/support/db/name_of_migration.rb +24 -0
- data/spec/support/invalid_interface_migration.rb +7 -0
- data/spec/support/not_a_migration.rb +2 -0
- data/spec/support/test_migration.rb +30 -0
- data/spec/units/mince_migrator/cli_helper_spec.rb +147 -0
- data/spec/units/mince_migrator/creator_spec.rb +80 -0
- data/spec/units/mince_migrator/deleter_spec.rb +52 -0
- data/spec/units/mince_migrator/list_spec.rb +53 -0
- data/spec/units/mince_migrator/migration_spec.rb +119 -0
- data/spec/units/mince_migrator/migrations/file_spec.rb +85 -0
- data/spec/units/mince_migrator/migrations/loader_spec.rb +47 -0
- data/spec/units/mince_migrator/migrations/name_spec.rb +47 -0
- data/spec/units/mince_migrator/migrations/runner_spec.rb +70 -0
- data/spec/units/mince_migrator/migrations/runner_validator_spec.rb +46 -0
- data/spec/units/mince_migrator/migrations/template_spec.rb +42 -0
- data/spec/units/mince_migrator/migrations/versioned_file_spec.rb +48 -0
- data/spec/units/mince_migrator/ran_migration_spec.rb +60 -0
- data/spec/units/mince_migrator/reverter_spec.rb +78 -0
- metadata +298 -26
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/mince_migrator.gemspec +0 -19
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative '../../../lib/mince_migrator/migration'
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
describe MinceMigrator::Migration do
|
6
|
+
subject { described_class.new(options) }
|
7
|
+
|
8
|
+
let(:options) { { klass: klass, name: name, relative_path: relative_path, path: path } }
|
9
|
+
let(:klass) { mock time_created: Time.now.utc - 550000 }
|
10
|
+
let(:name) { "name_of_migration" }
|
11
|
+
let(:relative_path) { mock }
|
12
|
+
let(:path) { mock }
|
13
|
+
|
14
|
+
its(:time_created) { should == klass.time_created }
|
15
|
+
its(:relative_path) { should == relative_path }
|
16
|
+
its(:path) { should == path }
|
17
|
+
its(:age) { should == '6d' }
|
18
|
+
|
19
|
+
it 'can run the migration' do
|
20
|
+
return_value = mock
|
21
|
+
klass.should_receive(:run).and_return(return_value)
|
22
|
+
subject.run.should == return_value
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can revert the migration' do
|
26
|
+
return_value = mock
|
27
|
+
klass.should_receive(:revert).and_return(return_value)
|
28
|
+
subject.revert.should == return_value
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when there is a record of the migration being ran' do
|
32
|
+
let(:ran_migration) { mock }
|
33
|
+
|
34
|
+
before do
|
35
|
+
MinceMigrator::RanMigration.stub(:find_by_name).with(subject.name).and_return(ran_migration)
|
36
|
+
end
|
37
|
+
|
38
|
+
its(:ran?) { should be_true }
|
39
|
+
its(:status) { should == 'ran' }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when there is not a record of the migration being ran' do
|
43
|
+
before do
|
44
|
+
MinceMigrator::RanMigration.stub(:find_by_name).with(subject.name).and_return(nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
its(:ran?) { should be_false }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe MinceMigrator::Migration, 'class methods:' do
|
52
|
+
describe 'Loading from a file' do
|
53
|
+
subject { described_class.load_from_file(path_to_file) }
|
54
|
+
|
55
|
+
let(:path_to_file) { mock }
|
56
|
+
let(:migration_file) { mock klass: mock, name: mock, full_relative_path: mock, full_path: mock }
|
57
|
+
let(:migration) { mock }
|
58
|
+
|
59
|
+
before do
|
60
|
+
described_class.stub(:new).with(klass: migration_file.klass, name: migration_file.name, relative_path: migration_file.full_relative_path, path: migration_file.full_path).and_return(migration)
|
61
|
+
MinceMigrator::Migrations::File.stub(:load_from_file).with(path_to_file).and_return(migration_file)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns a migration for the given migration file' do
|
65
|
+
subject.should == migration
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'loads the migration file into memory' do
|
69
|
+
MinceMigrator::Migrations::File.should_receive(:load_from_file).with(path_to_file).and_return(migration_file)
|
70
|
+
|
71
|
+
subject
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'Finding a migration for a given name' do
|
76
|
+
subject { described_class.find(name) }
|
77
|
+
|
78
|
+
let(:name) { mock }
|
79
|
+
|
80
|
+
context 'when the migration exists' do
|
81
|
+
let(:migration) { mock }
|
82
|
+
let(:migration_file) { mock }
|
83
|
+
|
84
|
+
before do
|
85
|
+
MinceMigrator::Migrations::File.stub(:find).with(name).and_return(migration_file)
|
86
|
+
MinceMigrator::Migration.stub(:new_from_file).with(migration_file).and_return(migration)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns the migration' do
|
90
|
+
subject.should == migration
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when the migration does not exist' do
|
95
|
+
before do
|
96
|
+
MinceMigrator::Migrations::File.stub(:find).with(name).and_return(nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns nothing' do
|
100
|
+
subject.should be_nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'initializing with a migration file' do
|
106
|
+
subject { described_class.new_from_file(file) }
|
107
|
+
|
108
|
+
let(:file) { mock klass: mock, name: mock, full_relative_path: mock, full_path: mock }
|
109
|
+
let(:migration) { mock }
|
110
|
+
|
111
|
+
before do
|
112
|
+
described_class.stub(:new).with(klass: file.klass, name: file.name, relative_path: file.full_relative_path, path: file.full_path).and_return(migration)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns the migration' do
|
116
|
+
subject.should == migration
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/file'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::File do
|
4
|
+
subject { described_class.new(name) }
|
5
|
+
|
6
|
+
let(:expected_class_name) { 'ChangeSpacesToUnderscores' }
|
7
|
+
let(:name) { "Change spaces to underscores" }
|
8
|
+
let(:migration_template) { mock render: mock }
|
9
|
+
let(:config) { MinceMigrator::Config }
|
10
|
+
let(:loader) { mock klass: mock, load: nil }
|
11
|
+
|
12
|
+
before do
|
13
|
+
MinceMigrator::Migrations::Template.stub(:new).with(expected_class_name).and_return(migration_template)
|
14
|
+
File.stub(:exists?).with(subject.full_path).and_return(false)
|
15
|
+
MinceMigrator::Migrations::Loader.stub(:new).with(full_path: subject.full_path, klass_name: subject.klass_name).and_return(loader)
|
16
|
+
end
|
17
|
+
|
18
|
+
its(:name) { should == "change_spaces_to_underscores" }
|
19
|
+
its(:filename) { should == "#{subject.name}.rb" }
|
20
|
+
its(:full_path) { should == File.join(config.migration_dir, subject.filename) }
|
21
|
+
its(:full_relative_path) { should == File.join(config.migration_relative_dir, subject.filename) }
|
22
|
+
its(:body) { should == migration_template.render }
|
23
|
+
its(:klass) { should == loader.klass }
|
24
|
+
|
25
|
+
it 'can load the migration file' do
|
26
|
+
loader.should_receive(:call)
|
27
|
+
|
28
|
+
subject.load
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when it has been written to the file system' do
|
32
|
+
before do
|
33
|
+
::File.stub(:exists?).with(subject.full_path).and_return(true)
|
34
|
+
end
|
35
|
+
|
36
|
+
its(:persisted?) { should be_true }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when it has not been written to the file system' do
|
40
|
+
before do
|
41
|
+
::File.stub(:exists?).with(subject.full_path).and_return(false)
|
42
|
+
end
|
43
|
+
|
44
|
+
its(:persisted?) { should be_false }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe MinceMigrator::Migrations::File, 'Class methods:' do
|
49
|
+
describe 'finding a file' do
|
50
|
+
subject { described_class.find(name) }
|
51
|
+
|
52
|
+
let(:name) { mock }
|
53
|
+
let(:file) { mock }
|
54
|
+
|
55
|
+
before do
|
56
|
+
described_class.stub(:new).with(name).and_return(file)
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when one exists' do
|
60
|
+
before do
|
61
|
+
file.stub(persisted?: true, load: nil)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns the file' do
|
65
|
+
subject.should == file
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'loads the migration class' do
|
69
|
+
file.should_receive(:load)
|
70
|
+
|
71
|
+
subject
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when one does not exist' do
|
76
|
+
before do
|
77
|
+
file.stub(persisted?: false)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns nothing' do
|
81
|
+
subject.should be_nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/loader'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::Loader do
|
4
|
+
subject { described_class.new full_path: full_path, klass_name: klass_name }
|
5
|
+
|
6
|
+
context 'when the file exists and is a mince migrator migration file' do
|
7
|
+
let(:full_path) { File.expand_path('../../../../support/test_migration.rb', __FILE__) }
|
8
|
+
let(:klass_name) { 'TestMigration' }
|
9
|
+
let(:expected_klass) { eval "::MinceMigrator::Migrations::#{klass_name}" }
|
10
|
+
|
11
|
+
its(:klass) { should == expected_klass }
|
12
|
+
|
13
|
+
it 'loads the migration into memory' do
|
14
|
+
subject.call
|
15
|
+
|
16
|
+
expected_klass.should == expected_klass
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when the file exists but is not a mince migrator migration file' do
|
21
|
+
let(:full_path) { File.expand_path('../../../../support/not_a_migration.rb', __FILE__) }
|
22
|
+
let(:klass_name) { 'Foo' }
|
23
|
+
|
24
|
+
it 'raises an exception' do
|
25
|
+
expect { subject.call }.to raise_exception('invalid migration')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when the file does not exist' do
|
30
|
+
let(:full_path) { File.expand_path('../../../../support/does_not_exist_migration.rb', __FILE__) }
|
31
|
+
let(:klass_name) { 'Foo' }
|
32
|
+
|
33
|
+
it 'raises an exception' do
|
34
|
+
expect { subject.call }.to raise_exception('migration does not exist')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when the migration does not have the required interface' do
|
39
|
+
let(:full_path) { File.expand_path('../../../../support/invalid_interface_migration.rb', __FILE__) }
|
40
|
+
let(:klass_name) { 'InvalidInterfaceMigration' }
|
41
|
+
|
42
|
+
it 'raises an exception' do
|
43
|
+
expect { subject.call }.to raise_exception('migration does not have all required methods (:run, :revert, and :time_created)')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/name'
|
2
|
+
|
3
|
+
module MinceMigrator
|
4
|
+
module Migrations
|
5
|
+
describe Name do
|
6
|
+
subject { described_class.new(name) }
|
7
|
+
|
8
|
+
invalid_names = [
|
9
|
+
{ in: '!@#$%^&*()', out: '' },
|
10
|
+
{ in: nil, out: nil },
|
11
|
+
{ in: '', out: '' }
|
12
|
+
]
|
13
|
+
|
14
|
+
valid_names = [
|
15
|
+
{ in: 'name', out: 'Name', filename: 'name.rb' },
|
16
|
+
{ in: 'name_of_migration', out: 'Name of migration', filename: 'name_of_migration.rb' },
|
17
|
+
{ in: 'name of migration', out: 'Name of migration', filename: 'name_of_migration.rb' },
|
18
|
+
{ in: '1Name Of Migration', out: 'Name of migration', filename: 'name_of_migration.rb' },
|
19
|
+
{ in: 'Name Of Migration 1!@#$%^&*()', out: 'Name of migration 1', filename: 'name_of_migration_1.rb' }
|
20
|
+
]
|
21
|
+
|
22
|
+
valid_names.each do |name_group|
|
23
|
+
context "when the name is '#{name_group[:in]}'" do
|
24
|
+
let(:name) { name_group[:in] }
|
25
|
+
|
26
|
+
its(:value) { should == name_group[:out] }
|
27
|
+
its(:filename) { should == name_group[:filename] }
|
28
|
+
its(:valid?) { should be_true }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
invalid_names.each do |name_group|
|
33
|
+
context "when the name is '#{name_group[:in]}'" do
|
34
|
+
let(:name) { name_group[:in] }
|
35
|
+
|
36
|
+
before do
|
37
|
+
subject.valid?
|
38
|
+
end
|
39
|
+
|
40
|
+
its(:value) { should == name_group[:out] }
|
41
|
+
its(:valid?) { should be_false }
|
42
|
+
its(:reasons_for_failure) { should == "Name is invalid, it must start with a character from A-Z or a-z" }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/runner'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::Runner do
|
4
|
+
subject { described_class.new(name: name) }
|
5
|
+
|
6
|
+
let(:name) { mock }
|
7
|
+
let(:validator) { mock }
|
8
|
+
|
9
|
+
before do
|
10
|
+
Mince::Config.interface = mock
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'initializing with a migration' do
|
14
|
+
subject { described_class.new(migration: migration) }
|
15
|
+
|
16
|
+
let(:migration) { mock name: 'asdf' }
|
17
|
+
|
18
|
+
its(:migration) { should == migration }
|
19
|
+
its(:name) { should == migration.name }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when the migration exists' do
|
23
|
+
let(:migration) { mock ran?: false, name: mock }
|
24
|
+
|
25
|
+
before do
|
26
|
+
MinceMigrator::Migrations::RunnerValidator.stub(:new).with(migration).and_return(validator)
|
27
|
+
MinceMigrator::Migration.stub(:find).with(name).and_return(migration)
|
28
|
+
validator.stub(call: true, errors: [])
|
29
|
+
end
|
30
|
+
|
31
|
+
its(:can_run_migration?) { should be_true }
|
32
|
+
|
33
|
+
context 'when it is ran' do
|
34
|
+
before do
|
35
|
+
migration.stub(:run)
|
36
|
+
MinceMigrator::RanMigration.stub(:create)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns true' do
|
40
|
+
subject.run_migration.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'runs the migration' do
|
44
|
+
migration.should_receive(:run)
|
45
|
+
|
46
|
+
subject.run_migration
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'stores the record that it has been ran' do
|
50
|
+
MinceMigrator::RanMigration.should_receive(:create).with(name: migration.name)
|
51
|
+
|
52
|
+
subject.run_migration
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the runner validator has errors' do
|
58
|
+
let(:errors) { [mock] }
|
59
|
+
let(:name) { mock }
|
60
|
+
|
61
|
+
before do
|
62
|
+
MinceMigrator::Migrations::RunnerValidator.stub(:new).with(nil).and_return(validator)
|
63
|
+
validator.stub(call: false, errors: errors)
|
64
|
+
MinceMigrator::Migration.stub(:find).with(name).and_return(nil)
|
65
|
+
end
|
66
|
+
|
67
|
+
its(:can_run_migration?) { should be_false }
|
68
|
+
its(:reasons_for_failure) { should == errors.join(' ') }
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/runner_validator'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::RunnerValidator do
|
4
|
+
subject { described_class.new(migration) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
Mince::Config.interface = mock
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'when the migration exists' do
|
11
|
+
let(:migration) { mock }
|
12
|
+
|
13
|
+
context 'when it has already ran' do
|
14
|
+
before do
|
15
|
+
migration.stub(ran?: true)
|
16
|
+
subject.call
|
17
|
+
end
|
18
|
+
|
19
|
+
its(:call) { should be_false }
|
20
|
+
its(:errors) { should == ['Migration has already ran'] }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when the migration does not exist' do
|
25
|
+
let(:migration) { nil }
|
26
|
+
|
27
|
+
before do
|
28
|
+
subject.call
|
29
|
+
end
|
30
|
+
|
31
|
+
its(:call) { should be_false }
|
32
|
+
its(:errors) { should == ['Migration does not exist'] }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when the mince interface is not set' do
|
36
|
+
let(:migration) { mock }
|
37
|
+
|
38
|
+
before do
|
39
|
+
Mince::Config.interface = nil
|
40
|
+
subject.call
|
41
|
+
end
|
42
|
+
|
43
|
+
its(:call) { should be_false }
|
44
|
+
its(:errors) { should == ['Mince interface is not set'] }
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/template'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::Template do
|
4
|
+
subject { described_class.new klass_name }
|
5
|
+
|
6
|
+
let(:klass_name) { 'NameOfMigration' }
|
7
|
+
let(:now) { mock 'time', to_s: "2013-02-23 19:03:27 UTC" }
|
8
|
+
|
9
|
+
before do
|
10
|
+
Time.stub_chain('now.utc' => now)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'renders the template' do
|
14
|
+
expected_content = <<-eos
|
15
|
+
module MinceMigrator
|
16
|
+
module Migrations
|
17
|
+
require 'time'
|
18
|
+
|
19
|
+
module #{klass_name}
|
20
|
+
def self.run
|
21
|
+
# Actual migration goes here
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.revert
|
25
|
+
# In case you need to revert this one migration
|
26
|
+
end
|
27
|
+
|
28
|
+
# So you can change the order to run more easily
|
29
|
+
def self.time_created
|
30
|
+
Time.parse "#{now.to_s}"
|
31
|
+
end
|
32
|
+
|
33
|
+
module Temporary
|
34
|
+
# Migration dependent classes go here
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
eos
|
40
|
+
subject.render.should == expected_content
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../../../../lib/mince_migrator/migrations/versioned_file'
|
2
|
+
|
3
|
+
describe MinceMigrator::Migrations::VersionedFile do
|
4
|
+
describe 'Getting the next version of a migration for a given name' do
|
5
|
+
subject { described_class.new(name).next_unused_version }
|
6
|
+
|
7
|
+
let(:migration_file) { mock full_path: mock, persisted?: false }
|
8
|
+
let(:name) { mock }
|
9
|
+
|
10
|
+
context 'when no migrations contain the same name' do
|
11
|
+
before do
|
12
|
+
MinceMigrator::Migrations::File.stub(:new).with(name).and_return(migration_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns the migration file' do
|
16
|
+
subject.should == migration_file
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when a single migration exists with the same name' do
|
21
|
+
let(:other_migration_file) { mock full_path: mock, persisted?: true }
|
22
|
+
|
23
|
+
before do
|
24
|
+
MinceMigrator::Migrations::File.stub(:new).with(name).and_return(other_migration_file)
|
25
|
+
MinceMigrator::Migrations::File.stub(:new).with("#{name}_2").and_return(migration_file)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns a migration file the second version' do
|
29
|
+
subject.should == migration_file
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when multiple migrations exist with the same name' do
|
34
|
+
let(:other_migration_file) { mock full_path: mock, persisted?: true }
|
35
|
+
let(:other_migration_file2) { mock full_path: mock, persisted?: true }
|
36
|
+
|
37
|
+
before do
|
38
|
+
MinceMigrator::Migrations::File.stub(:new).with(name).and_return(other_migration_file)
|
39
|
+
MinceMigrator::Migrations::File.stub(:new).with("#{name}_2").and_return(other_migration_file2)
|
40
|
+
MinceMigrator::Migrations::File.stub(:new).with("#{name}_3").and_return(migration_file)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns a migration file for the first unused version' do
|
44
|
+
subject.should == migration_file
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative '../../../lib/mince_migrator/ran_migration'
|
2
|
+
|
3
|
+
describe MinceMigrator::RanMigration do
|
4
|
+
let(:name) { "Name of migration" }
|
5
|
+
|
6
|
+
subject { described_class.new(name: name) }
|
7
|
+
|
8
|
+
its(:data_model) { should == MinceMigrator::RanMigrationDataModel }
|
9
|
+
its(:fields){ should == [:name] }
|
10
|
+
its(:name) { should == name }
|
11
|
+
|
12
|
+
it 'can be deleted' do
|
13
|
+
described_class.data_model.should_receive(:delete_by_params).with(name: name)
|
14
|
+
|
15
|
+
subject.delete
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe MinceMigrator::RanMigration, 'Class methods:' do
|
20
|
+
describe 'finding by name' do
|
21
|
+
subject { described_class.find_by_name(name) }
|
22
|
+
|
23
|
+
let(:name) { mock }
|
24
|
+
|
25
|
+
before do
|
26
|
+
described_class.data_model.stub(:find_by_field).with(:name, name).and_return(data)
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when it exists' do
|
30
|
+
let(:data) { mock }
|
31
|
+
let(:model) { mock }
|
32
|
+
|
33
|
+
before do
|
34
|
+
described_class.stub(:new).with(data).and_return(model)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns the model 'do
|
38
|
+
subject.should == model
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when it does not exist 'do
|
43
|
+
let(:data) { nil }
|
44
|
+
|
45
|
+
it 'returns nil' do
|
46
|
+
subject.should be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe MinceMigrator::RanMigrationDataModel do
|
53
|
+
it 'stores everything in the "migrations" collection' do
|
54
|
+
described_class.data_collection.should == :migrations
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has the name field' do
|
58
|
+
described_class.data_fields.should == [:name]
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative '../../../lib/mince_migrator/reverter'
|
2
|
+
|
3
|
+
describe MinceMigrator::Reverter do
|
4
|
+
subject { described_class.new(name: name) }
|
5
|
+
|
6
|
+
let(:name) { mock }
|
7
|
+
let(:migration_name) { mock value: mock }
|
8
|
+
|
9
|
+
before do
|
10
|
+
MinceMigrator::Migrations::Name.stub(:new).with(name).and_return(migration_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'initializing with a migration' do
|
14
|
+
subject { described_class.new(migration: migration) }
|
15
|
+
|
16
|
+
let(:migration) { mock name: name }
|
17
|
+
|
18
|
+
its(:migration) { should == migration }
|
19
|
+
its(:name) { should == migration_name.value }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when the migration does not exist' do
|
23
|
+
before do
|
24
|
+
MinceMigrator::Migration.stub(:find).with(migration_name.value).and_return(nil)
|
25
|
+
subject.can_revert_migration?
|
26
|
+
end
|
27
|
+
|
28
|
+
its(:can_revert_migration?) { should be_false }
|
29
|
+
its(:reasons_for_failure) { should == "Migration does not exist with name '#{migration_name.value}'" }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the migration exists' do
|
33
|
+
let(:migration) { mock name: mock }
|
34
|
+
|
35
|
+
before do
|
36
|
+
MinceMigrator::Migration.stub(:find).with(migration_name.value).and_return(migration)
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'and has been ran' do
|
40
|
+
let(:ran_migration) { mock }
|
41
|
+
|
42
|
+
before do
|
43
|
+
migration.stub(ran?: true, ran_migration: ran_migration)
|
44
|
+
migration.stub(:revert)
|
45
|
+
ran_migration.stub(:delete)
|
46
|
+
end
|
47
|
+
|
48
|
+
its(:can_revert_migration?) { should be_true }
|
49
|
+
|
50
|
+
it 'returns true' do
|
51
|
+
subject.revert_migration.should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'reverts the migration' do
|
55
|
+
migration.should_receive(:revert)
|
56
|
+
|
57
|
+
subject.revert_migration
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'deletes the ran migration' do
|
61
|
+
ran_migration.should_receive(:delete)
|
62
|
+
|
63
|
+
subject.revert_migration
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'but has not been ran' do
|
68
|
+
before do
|
69
|
+
migration.stub(ran?: false)
|
70
|
+
|
71
|
+
subject.can_revert_migration?
|
72
|
+
end
|
73
|
+
|
74
|
+
its(:can_revert_migration?) { should be_false }
|
75
|
+
its(:reasons_for_failure) { should == "Migration has not ran" }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|