discourse/spec/components/migration/table_dropper_spec.rb
Guo Xiang Tan 40fa96777d
FEATURE: Post deployment migrations. (#6406)
This moves us away from the delayed drops pattern which
was problematic on two counts. First, it uses a hardcoded "delay for"
duration which may be too short for certain deployment strategies.
Second, delayed drop doesn't ensure that it only runs after
the latest application code has been deployed. If the migration runs
and the application code fails to deploy, running the migration after
"delay for" has been met will cause the application to blow up.

The new strategy allows post deployment migrations to be skipped if the
env `SKIP_POST_DEPLOYMENT_MIGRATIONS` is provided.

```
SKIP_POST_DEPLOYMENT_MIGRATIONS=1 rake db:migrate
-> deploy app servers
SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate
```

To aid with the generation of a post deployment migration, a generator
has been added. Simply run `rails generate post_migration`.
2018-10-08 15:47:38 +08:00

73 lines
1.7 KiB
Ruby

require 'rails_helper'
require_dependency 'migration/table_dropper'
describe Migration::TableDropper do
def table_exists?(table_name)
DB.exec(<<~SQL) > 0
SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema = 'public' AND
table_name = '#{table_name}'
SQL
end
let(:table_name) { 'table_with_old_name' }
before do
DB.exec "CREATE TABLE #{table_name} (topic_id INTEGER)"
DB.exec <<~SQL
INSERT INTO #{table_name} (topic_id) VALUES (1)
SQL
end
describe ".execute_drop" do
it "should drop the table" do
Migration::TableDropper.execute_drop(table_name)
expect(table_exists?(table_name)).to eq(false)
end
end
describe ".readonly_only_table" do
before do
Migration::TableDropper.read_only_table(table_name)
end
after do
ActiveRecord::Base.connection.reset!
DB.exec(<<~SQL)
DROP TABLE IF EXISTS #{table_name};
DROP FUNCTION IF EXISTS #{Migration::BaseDropper.readonly_function_name(table_name)} CASCADE;
SQL
end
it 'should be droppable' do
Migration::TableDropper.execute_drop(table_name)
expect(has_trigger?(Migration::BaseDropper.readonly_trigger_name(
table_name
))).to eq(false)
expect(table_exists?(table_name)).to eq(false)
end
it 'should prevent insertions to the table' do
begin
DB.exec <<~SQL
INSERT INTO #{table_name} (topic_id) VALUES (2)
SQL
rescue PG::RaiseException => e
[
"Discourse: #{table_name} is read only",
'discourse_functions.raise_table_with_old_name_readonly()'
].each do |message|
expect(e.message).to include(message)
end
end
end
end
end