# frozen_string_literal: true require 'spec_helper' RSpec.describe 'gitlab:clickhouse', click_house: :without_migrations, feature_category: :database do include ClickHouseTestHelpers # We don't need to delete data since we don't modify Postgres data self.use_transactional_tests = false before(:all) do Rake.application.rake_require 'tasks/gitlab/click_house/migration' end it 'migrates and rolls back the database' do expect { run_rake_task('gitlab:clickhouse:migrate:main') }.to change { active_schema_migrations_count }.from(0) .and output.to_stdout expect { run_rake_task('gitlab:clickhouse:rollback:main') }.to change { active_schema_migrations_count }.by(-1) .and output.to_stdout stub_env('VERSION', 0) expect { run_rake_task('gitlab:clickhouse:rollback:main') }.to change { active_schema_migrations_count }.to(0) .and output.to_stdout end context 'when clickhouse database is not configured' do before do allow(::ClickHouse::Client).to receive(:configuration).and_return(::ClickHouse::Client::Configuration.new) end it 'raises an error' do expect { run_rake_task('gitlab:clickhouse:migrate:main') }.to raise_error(ClickHouse::Client::ConfigurationError) end it 'prints the error message and exits successfully if skip_unless_configured is passed' do expect do run_rake_task('gitlab:clickhouse:migrate:main', true) end.to output(/The 'main' ClickHouse database is not configured, skipping migrations/).to_stdout end end describe 'gitlab:clickhouse:migrate' do it 'delegates to gitlab:clickhouse:migrate:main' do task = Rake::Task['gitlab:clickhouse:migrate:main'] task.reenable # re-enabling task in case other tests already run it expect(task).to receive(:invoke).with("true").and_call_original expect do run_rake_task('gitlab:clickhouse:migrate', true) end.to change { active_schema_migrations_count }.from(0).and output.to_stdout end end context 'with migration fixtures', :silence_stdout do let(:migrations_base_dir) { 'click_house/migrations' } let(:migrations_dirname) { 'undefined' } let(:migrations_dir) { expand_fixture_path("#{migrations_base_dir}/#{migrations_dirname}") } describe 'migrate:main' do subject(:migration) { run_rake_task('gitlab:clickhouse:migrate:main') } let(:verbose) { nil } let(:target_version) { nil } let(:step) { nil } before do allow(ClickHouse::MigrationSupport::Migrator).to receive(:migrations_paths).with(:main) .and_return(migrations_dir) stub_env('VERBOSE', verbose) if verbose stub_env('VERSION', target_version) if target_version stub_env('STEP', step.to_s) if step end after do unload_click_house_migration_classes(expand_fixture_path(migrations_dir)) end describe 'when creating a table' do let(:migrations_dirname) { 'plain_table_creation' } it 'creates a table' do expect { migration }.to change { active_schema_migrations_count }.from(0).to(1) .and output.to_stdout expect(describe_table('some')).to match({ id: a_hash_including(type: 'UInt64'), date: a_hash_including(type: 'Date') }) end context 'when VERBOSE is false' do let(:verbose) { 'false' } it 'does not write to stdout' do expect { migration }.not_to output.to_stdout expect(describe_table('some')).to match({ id: a_hash_including(type: 'UInt64'), date: a_hash_including(type: 'Date') }) end end end describe 'when dropping a table' do let(:migrations_dirname) { 'drop_table' } context 'with VERSION set' do let(:target_version) { 2 } it 'drops table' do stub_env('VERSION', 1) run_rake_task('gitlab:clickhouse:migrate:main') expect(table_names).to include('some') stub_env('VERSION', target_version) migration expect(table_names).not_to include('some') end context 'with STEP also set' do let(:step) { 1 } it 'ignores STEP and executes both migrations' do migration expect(table_names).not_to include('some') end end end context 'with STEP set to 1' do let(:step) { 1 } it 'executes only first step and creates table' do migration expect(table_names).to include('some') end end context 'with STEP set to 0' do let(:step) { 0 } it 'executes only first step and creates table' do expect { migration }.to raise_error ArgumentError, 'STEP should be a positive number' end end context 'with STEP set to not-a-number' do let(:step) { 'NaN' } it 'raises an error' do expect { migration }.to raise_error ArgumentError, 'invalid value for Integer(): "NaN"' end end context 'with STEP set to empty string' do let(:step) { '' } it 'raises an error' do expect { migration }.to raise_error ArgumentError, 'invalid value for Integer(): ""' end end end context 'with VERSION is invalid' do let(:migrations_dirname) { 'plain_table_creation' } let(:target_version) { 'invalid' } it { expect { migration }.to raise_error RuntimeError, 'Invalid format of target version: `VERSION=invalid`' } end end describe 'rollback:main' do subject(:migration) { run_rake_task('gitlab:clickhouse:rollback:main') } let(:target_version) { nil } let(:rollback_step) { nil } let(:migrations_dirname) { 'table_creation_with_down_method' } before do allow(ClickHouse::MigrationSupport::Migrator).to receive(:migrations_paths).with(:main) .and_return(migrations_dir) run_rake_task('gitlab:clickhouse:migrate:main') stub_env('VERSION', target_version) if target_version stub_env('STEP', rollback_step.to_s) if rollback_step end after do unload_click_house_migration_classes(expand_fixture_path(migrations_dir)) end context 'with VERSION set' do context 'when migrating back all the way to 0' do let(:target_version) { 0 } it 'rolls back all migrations' do expect(table_names).to include('some', 'another') migration expect(table_names).not_to include('some', 'another') end context 'with STEP also set' do let(:rollback_step) { 1 } it 'ignores STEP and rolls back all migrations' do expect(table_names).to include('some', 'another') migration expect(table_names).not_to include('some', 'another') end end end end context 'with STEP set to 1' do let(:rollback_step) { 1 } it 'executes only first step and drops "another" table' do run_rake_task('gitlab:clickhouse:rollback:main') expect(table_names).to include('some') expect(table_names).not_to include('another') end end end end end