Skip to content

Commit c5f92e2

Browse files
committed
Improve migration and add migration tests
1 parent 15421b3 commit c5f92e2

4 files changed

+245
-54
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
Sequel.migration do
2+
up do
3+
if database_type == :postgres
4+
alter_table :apps do
5+
add_column :service_binding_k8s_enabled, :boolean, default: false, null: false, if_not_exists: true
6+
add_column :file_based_vcap_services_enabled, :boolean, default: false, null: false, if_not_exists: true
7+
8+
unless check_constraint_exists?(@db)
9+
add_constraint(name: :only_one_sb_feature_enabled, if_not_exists: true) do
10+
Sequel.lit('NOT (service_binding_k8s_enabled AND file_based_vcap_services_enabled)')
11+
end
12+
end
13+
end
14+
15+
elsif database_type == :mysql
16+
add_column :apps, :service_binding_k8s_enabled, :boolean, default: false, null: false unless schema(:apps).map(&:first).include?(:service_binding_k8s_enabled)
17+
add_column :apps, :file_based_vcap_services_enabled, :boolean, default: false, null: false unless schema(:apps).map(&:first).include?(:file_based_vcap_services_enabled)
18+
19+
unless check_constraint_exists?(self)
20+
run('ALTER TABLE apps ADD CONSTRAINT only_one_sb_feature_enabled CHECK (NOT (service_binding_k8s_enabled AND file_based_vcap_services_enabled))')
21+
end
22+
end
23+
end
24+
25+
down do
26+
alter_table :apps do
27+
drop_constraint :only_one_sb_feature_enabled if check_constraint_exists?(@db)
28+
drop_column :service_binding_k8s_enabled if @db.schema(:apps).map(&:first).include?(:service_binding_k8s_enabled)
29+
drop_column :file_based_vcap_services_enabled if @db.schema(:apps).map(&:first).include?(:file_based_vcap_services_enabled)
30+
end
31+
end
32+
end
33+
34+
def check_constraint_exists?(database)
35+
if database.database_type == :postgres
36+
database.check_constraints(:apps).include?(:only_one_sb_feature_enabled)
37+
elsif database.database_type == :mysql
38+
database[:information_schema__table_constraints].where(TABLE_NAME: 'apps', CONSTRAINT_TYPE: 'CHECK', CONSTRAINT_NAME: 'only_one_sb_feature_enabled').any?
39+
end
40+
end

db/migrations/20250225132929_add_apps_service_binding_k8s_enabled_column.rb

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
require 'spec_helper'
2+
require 'migrations/helpers/migration_shared_context'
3+
4+
RSpec.describe 'migration to add service_binding_k8s_enabled column to apps table', isolation: :truncation, type: :migration do
5+
include_context 'migration' do
6+
let(:migration_filename) { '20250225132929_add_apps_file_based_service_binding_feature_columns.rb' }
7+
end
8+
9+
describe 'apps table' do
10+
subject(:run_migration) { Sequel::Migrator.run(db, migrations_path, target: current_migration_index, allow_missing_migration_files: true) }
11+
12+
describe 'up' do
13+
describe 'column service_binding_k8s_enabled' do
14+
it 'adds a column `service_binding_k8s_enabled`' do
15+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
16+
run_migration
17+
expect(db[:apps].columns).to include(:service_binding_k8s_enabled)
18+
end
19+
20+
it 'sets the default value of existing entries to false' do
21+
db[:apps].insert(guid: 'existing_app_guid')
22+
run_migration
23+
expect(db[:apps].first(guid: 'existing_app_guid')[:service_binding_k8s_enabled]).to be(false)
24+
end
25+
26+
it 'sets the default value of new entries to false' do
27+
run_migration
28+
db[:apps].insert(guid: 'new_app_guid')
29+
expect(db[:apps].first(guid: 'new_app_guid')[:service_binding_k8s_enabled]).to be(false)
30+
end
31+
32+
it 'forbids null values' do
33+
run_migration
34+
expect { db[:apps].insert(guid: 'app_guid__nil', service_binding_k8s_enabled: nil) }.to raise_error(Sequel::NotNullConstraintViolation)
35+
end
36+
37+
context 'when it already exists' do
38+
before do
39+
db.add_column :apps, :service_binding_k8s_enabled, :boolean, default: false, null: false, if_not_exists: true
40+
end
41+
42+
it 'does not fail' do
43+
expect(db[:apps].columns).to include(:service_binding_k8s_enabled)
44+
expect { run_migration }.not_to raise_error
45+
expect(db[:apps].columns).to include(:service_binding_k8s_enabled)
46+
expect(db[:apps].columns).to include(:file_based_vcap_services_enabled)
47+
expect(check_constraint_exists?(db)).to be(true)
48+
end
49+
end
50+
end
51+
52+
describe 'column file_based_vcap_services_enabled' do
53+
it 'adds a column `file_based_vcap_services_enabled`' do
54+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
55+
run_migration
56+
expect(db[:apps].columns).to include(:file_based_vcap_services_enabled)
57+
end
58+
59+
it 'sets the default value of existing entries to false' do
60+
db[:apps].insert(guid: 'existing_app_guid')
61+
run_migration
62+
expect(db[:apps].first(guid: 'existing_app_guid')[:file_based_vcap_services_enabled]).to be(false)
63+
end
64+
65+
it 'sets the default value of new entries to false' do
66+
run_migration
67+
db[:apps].insert(guid: 'new_app_guid')
68+
expect(db[:apps].first(guid: 'new_app_guid')[:file_based_vcap_services_enabled]).to be(false)
69+
end
70+
71+
it 'forbids null values' do
72+
run_migration
73+
expect { db[:apps].insert(guid: 'app_guid__nil', file_based_vcap_services_enabled: nil) }.to raise_error(Sequel::NotNullConstraintViolation)
74+
end
75+
76+
context 'when it already exists' do
77+
before do
78+
db.add_column :apps, :file_based_vcap_services_enabled, :boolean, default: false, null: false, if_not_exists: true
79+
end
80+
81+
it 'does not fail' do
82+
expect(db[:apps].columns).to include(:file_based_vcap_services_enabled)
83+
expect { run_migration }.not_to raise_error
84+
expect(db[:apps].columns).to include(:service_binding_k8s_enabled)
85+
expect(db[:apps].columns).to include(:file_based_vcap_services_enabled)
86+
expect(check_constraint_exists?(db)).to be(true)
87+
end
88+
end
89+
end
90+
91+
describe 'check constraint' do
92+
it 'adds the check constraint' do
93+
expect(check_constraint_exists?(db)).to be(false)
94+
run_migration
95+
expect(check_constraint_exists?(db)).to be(true)
96+
end
97+
98+
it 'forbids setting both features to true' do
99+
run_migration
100+
expect { db[:apps].insert(guid: 'some_app', file_based_vcap_services_enabled: true, service_binding_k8s_enabled: true) }.to(raise_error do |error|
101+
expect(error.inspect).to include('only_one_sb_feature_enabled', 'violate')
102+
end)
103+
end
104+
105+
context 'when it already exists' do
106+
before do
107+
db.add_column :apps, :service_binding_k8s_enabled, :boolean, default: false, null: false, if_not_exists: true
108+
db.add_column :apps, :file_based_vcap_services_enabled, :boolean, default: false, null: false, if_not_exists: true
109+
db.alter_table :apps do
110+
add_constraint(name: :only_one_sb_feature_enabled) do
111+
Sequel.lit('NOT (service_binding_k8s_enabled AND file_based_vcap_services_enabled)')
112+
end
113+
end
114+
end
115+
116+
it 'does not fail' do
117+
expect { run_migration }.not_to raise_error
118+
end
119+
end
120+
end
121+
end
122+
123+
describe 'down' do
124+
subject(:run_rollback) { Sequel::Migrator.run(db, migrations_path, target: current_migration_index - 1, allow_missing_migration_files: true) }
125+
126+
before do
127+
run_migration
128+
end
129+
130+
describe 'column service_binding_k8s_enabled' do
131+
it 'removes column `service_binding_k8s_enabled`' do
132+
expect(db[:apps].columns).to include(:service_binding_k8s_enabled)
133+
run_rollback
134+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
135+
end
136+
137+
context 'when it does not exist' do
138+
before do
139+
db.alter_table :apps do
140+
drop_constraint :only_one_sb_feature_enabled
141+
drop_column :service_binding_k8s_enabled
142+
end
143+
end
144+
145+
it 'does not fail' do
146+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
147+
expect { run_rollback }.not_to raise_error
148+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
149+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
150+
expect(check_constraint_exists?(db)).to be(false)
151+
end
152+
end
153+
end
154+
155+
describe 'column file_based_vcap_services_enabled' do
156+
it 'removes column `file_based_vcap_services_enabled`' do
157+
expect(db[:apps].columns).to include(:file_based_vcap_services_enabled)
158+
run_rollback
159+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
160+
end
161+
162+
context 'when it does not exist' do
163+
before do
164+
db.alter_table :apps do
165+
drop_constraint :only_one_sb_feature_enabled
166+
drop_column :file_based_vcap_services_enabled
167+
end
168+
end
169+
170+
it 'does not fail' do
171+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
172+
expect { run_rollback }.not_to raise_error
173+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
174+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
175+
expect(check_constraint_exists?(db)).to be(false)
176+
end
177+
end
178+
end
179+
180+
describe 'check constraint' do
181+
it 'removes the check constraint' do
182+
expect(check_constraint_exists?(db)).to be(true)
183+
run_rollback
184+
expect(check_constraint_exists?(db)).to be(false)
185+
end
186+
187+
context 'when it does not exist' do
188+
before do
189+
db.alter_table :apps do
190+
drop_constraint :only_one_sb_feature_enabled
191+
end
192+
end
193+
194+
it 'does not fail' do
195+
expect(check_constraint_exists?(db)).to be(false)
196+
expect { run_rollback }.not_to raise_error
197+
expect(db[:apps].columns).not_to include(:service_binding_k8s_enabled)
198+
expect(db[:apps].columns).not_to include(:file_based_vcap_services_enabled)
199+
expect(check_constraint_exists?(db)).to be(false)
200+
end
201+
end
202+
end
203+
end
204+
end
205+
end

spec/migrations/20250225132929_add_apps_service_binding_k8s_enabled_column_spec.rb

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)