mince_migrator 0.0.1 → 1.0.0
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.
- 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
|