このコミットが含まれているのは:
@@ -0,0 +1,123 @@
|
||||
require 'rails_helper'
|
||||
require_relative '../../db/migrate/20260921020000_delete_discarded_records_from_tags'
|
||||
require_relative '../../db/migrate/20260921030000_delete_discarded_records_from_tag_names'
|
||||
|
||||
RSpec.describe 'discarded tag cleanup migrations' do
|
||||
[DeleteDiscardedRecordsFromTags, DeleteDiscardedRecordsFromTagNames].each do |migration_class|
|
||||
it "rejects rollback of #{ migration_class.name }" do
|
||||
expect { migration_class.new.down }
|
||||
.to raise_error(ActiveRecord::IrreversibleMigration)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with legacy records' do
|
||||
self.use_transactional_tests = false
|
||||
|
||||
before do
|
||||
record_class = Class.new(ActiveRecord::Base) do
|
||||
self.abstract_class = true
|
||||
end
|
||||
stub_const('TagCleanupMigrationRecord', record_class)
|
||||
config = ActiveRecord::Base.connection_db_config.configuration_hash
|
||||
@database = "btrc_hub_test_tag_cleanup_#{ Process.pid }_#{ SecureRandom.hex(4) }"
|
||||
record_class.establish_connection(config.merge(database: nil))
|
||||
@connection = record_class.lease_connection
|
||||
@connection.create_database(@database)
|
||||
@database_created = true
|
||||
@connection.execute("USE #{ @connection.quote_table_name(@database) }")
|
||||
end
|
||||
|
||||
after do
|
||||
@connection.drop_database(@database) if @database_created
|
||||
ensure
|
||||
TagCleanupMigrationRecord.remove_connection
|
||||
end
|
||||
|
||||
before do
|
||||
@connection.create_table(:tag_names) do |t|
|
||||
t.string :name, null: false, index: { unique: true }
|
||||
t.bigint :canonical_id
|
||||
t.datetime :discarded_at, index: true
|
||||
end
|
||||
@connection.add_foreign_key(:tag_names, :tag_names, column: :canonical_id)
|
||||
@connection.create_table(:tags) do |t|
|
||||
t.references :tag_name, null: false, foreign_key: true, index: { unique: true }
|
||||
t.datetime :discarded_at, index: true
|
||||
end
|
||||
@connection.create_table(:nico_tag_relations) do |t|
|
||||
t.references :tag, null: false, foreign_key: true
|
||||
t.references :nico_tag, null: false, foreign_key: { to_table: :tags }
|
||||
end
|
||||
@connection.create_table(:tag_implications) do |t|
|
||||
t.references :tag, null: false, foreign_key: true
|
||||
t.references :parent_tag, null: false, foreign_key: { to_table: :tags }
|
||||
end
|
||||
[:tag_versions, :nico_tag_versions, :material_versions].each do |table|
|
||||
@connection.create_table(table) do |t|
|
||||
t.references :tag, null: false, foreign_key: true
|
||||
end
|
||||
end
|
||||
|
||||
@connection.execute(<<~SQL)
|
||||
INSERT INTO tag_names (id, name, canonical_id, discarded_at) VALUES
|
||||
(1, 'kept', NULL, NULL),
|
||||
(2, 'merged_alias', 1, NULL),
|
||||
(3, 'nico:deleted', NULL, '2026-09-20'),
|
||||
(4, 'nico:kept', NULL, NULL),
|
||||
(5, 'deleted_name', NULL, '2026-09-20')
|
||||
SQL
|
||||
@connection.execute(<<~SQL)
|
||||
INSERT INTO tags (id, tag_name_id, discarded_at) VALUES
|
||||
(1, 1, NULL), (2, 2, '2026-09-20'),
|
||||
(3, 3, '2026-09-20'), (4, 4, NULL)
|
||||
SQL
|
||||
@connection.execute(<<~SQL)
|
||||
INSERT INTO nico_tag_relations (id, tag_id, nico_tag_id) VALUES
|
||||
(1, 1, 4), (2, 2, 4), (3, 1, 3), (4, 2, 3)
|
||||
SQL
|
||||
@connection.execute(<<~SQL)
|
||||
INSERT INTO tag_implications (id, tag_id, parent_tag_id) VALUES
|
||||
(1, 1, 4), (2, 2, 1), (3, 1, 2), (4, 2, 3)
|
||||
SQL
|
||||
@connection.execute('INSERT INTO tag_versions (tag_id) VALUES (1), (2)')
|
||||
@connection.execute('INSERT INTO nico_tag_versions (tag_id) VALUES (3), (4)')
|
||||
@connection.execute('INSERT INTO material_versions (tag_id) VALUES (1), (2)')
|
||||
end
|
||||
|
||||
it 'removes discarded records and their links while retaining aliases and history' do
|
||||
[DeleteDiscardedRecordsFromTags, DeleteDiscardedRecordsFromTagNames].each do |klass|
|
||||
migration = klass.new
|
||||
allow(migration).to receive(:connection).and_return(@connection)
|
||||
migration.suppress_messages { migration.up }
|
||||
end
|
||||
|
||||
expect(@connection.select_values('SELECT id FROM tags ORDER BY id')).to eq([1, 4])
|
||||
expect(@connection.select_rows('SELECT id, canonical_id FROM tag_names ORDER BY id'))
|
||||
.to eq([[1, nil], [2, 1], [4, nil]])
|
||||
expect(@connection.select_values('SELECT id FROM nico_tag_relations')).to eq([1])
|
||||
expect(@connection.select_values('SELECT id FROM tag_implications')).to eq([1])
|
||||
expect(@connection.select_values('SELECT tag_id FROM tag_versions ORDER BY tag_id'))
|
||||
.to eq([1, 2])
|
||||
expect(@connection.select_values('SELECT tag_id FROM nico_tag_versions ORDER BY tag_id'))
|
||||
.to eq([3, 4])
|
||||
expect(@connection.select_values('SELECT tag_id FROM material_versions ORDER BY tag_id'))
|
||||
.to eq([1, 2])
|
||||
|
||||
[:tags, :tag_names].each do |table|
|
||||
expect(@connection.column_exists?(table, :discarded_at)).to be(false)
|
||||
expect(@connection.index_exists?(table, :discarded_at)).to be(false)
|
||||
end
|
||||
[:tag_versions, :nico_tag_versions, :material_versions].each do |table|
|
||||
expect(@connection.foreign_key_exists?(table, :tags, column: :tag_id)).to be(false)
|
||||
end
|
||||
expect(@connection.foreign_key_exists?(:tags, :tag_names)).to be(true)
|
||||
expect(@connection.foreign_key_exists?(:tag_names, :tag_names, column: :canonical_id))
|
||||
.to be(true)
|
||||
expect(@connection.index_exists?(:tag_names, :name, unique: true)).to be(true)
|
||||
expect(@connection.index_exists?(:tags, :tag_name_id, unique: true)).to be(true)
|
||||
[:nico_tag_relations, :tag_implications].each do |table|
|
||||
expect(@connection.foreign_keys(table).map(&:to_table)).to eq(['tags', 'tags'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
新しいイシューから参照
ユーザーをブロックする