From 06c6d414fc2be3dcfb380a99a750d6f2c19f2a9f Mon Sep 17 00:00:00 2001 From: Carlos Palhares Date: Thu, 8 Feb 2024 15:56:17 -0300 Subject: [PATCH] Test Percona Adapter with Trilogy backend --- .../percona_adapter_spec.rb | 444 +++++++++--------- 1 file changed, 227 insertions(+), 217 deletions(-) diff --git a/spec/active_record/connection_adapters/percona_adapter_spec.rb b/spec/active_record/connection_adapters/percona_adapter_spec.rb index 13804038..c9033462 100644 --- a/spec/active_record/connection_adapters/percona_adapter_spec.rb +++ b/spec/active_record/connection_adapters/percona_adapter_spec.rb @@ -1,278 +1,288 @@ require 'spec_helper' -describe ActiveRecord::ConnectionAdapters::DepartureAdapter do - let(:mysql_adapter) do - instance_double(ActiveRecord::ConnectionAdapters::Mysql2Adapter) - end - - let(:logger) { double(:logger, puts: true) } - let(:connection_options) { { mysql_adapter: mysql_adapter } } +require 'active_record/connection_adapters/mysql2_adapter' +require 'active_record/connection_adapters/trilogy_adapter' - let(:runner) { instance_double(Departure::Runner) } - let(:cli_generator) do - instance_double( - Departure::CliGenerator, - generate: 'percona command' - ) - end - - let(:config) { { prepared_statements: '', runner: runner } } +describe ActiveRecord::ConnectionAdapters::DepartureAdapter do + shared_examples_for ActiveRecord::ConnectionAdapters::DepartureAdapter do |adapter_class, result_class| + let(:mysql_client) { double(:mysql_client, server_info: { version: '5.7.19' }) } + let(:mysql_adapter) do + instance_double(adapter_class, raw_connection: mysql_client) + end + let(:logger) { double(:logger, puts: true) } + let(:connection_options) { { mysql_adapter: mysql_adapter } } + + let(:runner) { instance_double(Departure::Runner) } + let(:cli_generator) do + instance_double( + Departure::CliGenerator, + generate: 'percona command' + ) + end - let(:adapter) do - described_class.new(runner, logger, connection_options, config) - end + let(:config) { { prepared_statements: '', runner: runner } } - let(:mysql_client) { double(:mysql_client) } - - before do - allow(mysql_client).to receive(:server_info).and_return(version: '5.7.19') - allow(mysql_adapter).to receive(:raw_connection).and_return(mysql_client) - allow(runner).to( - receive(:execute).with('percona command').and_return(true) - ) - allow(Departure::CliGenerator).to( - receive(:new).and_return(cli_generator) - ) - allow(Departure::Runner).to( - receive(:new).with(logger) - ).and_return(runner) - end + subject(:adapter) do + described_class.new(runner, logger, connection_options, config) + end - describe '#supports_migrations?' do - subject { adapter.supports_migrations? } - it { is_expected.to be true } - end + before do + allow(runner).to( + receive(:execute).with('percona command').and_return(true) + ) + allow(Departure::CliGenerator).to( + receive(:new).and_return(cli_generator) + ) + allow(Departure::Runner).to( + receive(:new).with(logger) + ).and_return(runner) + end - describe '#new_column' do - let(:field) { double(:field) } - let(:default) { double(:default) } - let(:type) { double(:type) } - let(:null) { double(:null) } - let(:collation) { double(:collation) } - let(:table_name) { double(:table_name) } - let(:default_function) { double(:default_function) } - let(:comment) { double(:comment) } - - it do - expect(ActiveRecord::ConnectionAdapters::DepartureAdapter::Column).to receive(:new) - adapter.new_column(field, default, type, null, table_name, default_function, collation, comment) + it { is_expected.to be_supports_migrations } + + describe '#new_column' do + let(:field) { double(:field) } + let(:default) { double(:default) } + let(:type) { double(:type) } + let(:null) { double(:null) } + let(:collation) { double(:collation) } + let(:table_name) { double(:table_name) } + let(:default_function) { double(:default_function) } + let(:comment) { double(:comment) } + + it do + expect(ActiveRecord::ConnectionAdapters::DepartureAdapter::Column).to receive(:new) + subject.new_column(field, default, type, null, table_name, default_function, collation, comment) + end end - end - describe 'schema statements' do - describe '#add_index' do - let(:table_name) { :foo } - let(:column_name) { :bar_id } - let(:index_name) { 'index_name' } - let(:options) { {type: 'index_type'} } - let(:index_type) { options[:type].upcase } - let(:sql) { 'ADD index_type INDEX `index_name` (bar_id)' } - let(:index_options) do - if ActiveRecord::VERSION::STRING >= '6.1' - [ - ActiveRecord::ConnectionAdapters::IndexDefinition.new( - table_name, - index_name, + describe 'schema statements' do + describe '#add_index' do + let(:table_name) { :foo } + let(:column_name) { :bar_id } + let(:index_name) { 'index_name' } + let(:options) { {type: 'index_type'} } + let(:index_type) { options[:type].upcase } + let(:sql) { 'ADD index_type INDEX `index_name` (bar_id)' } + let(:index_options) do + if ActiveRecord::VERSION::STRING >= '6.1' + [ + ActiveRecord::ConnectionAdapters::IndexDefinition.new( + table_name, + index_name, + nil, + [column_name], + **options + ), nil, - [column_name], - **options - ), - nil, - false - ] - else - [index_name, index_type, "#{column_name}"] + false + ] + else + [index_name, index_type, "#{column_name}"] + end end - end - let(:expected_sql) do - if ActiveRecord::VERSION::STRING >= '6.1' - "ALTER TABLE `#{table_name}` ADD #{index_type} INDEX `#{index_name}` (`#{column_name}`)" - else - "ALTER TABLE `#{table_name}` ADD #{index_type} INDEX `#{index_name}` (#{column_name})" + let(:expected_sql) do + if ActiveRecord::VERSION::STRING >= '6.1' + "ALTER TABLE `#{table_name}` ADD #{index_type} INDEX `#{index_name}` (`#{column_name}`)" + else + "ALTER TABLE `#{table_name}` ADD #{index_type} INDEX `#{index_name}` (#{column_name})" + end end - end - before do - allow(adapter).to( - receive(:add_index_options) - .with(table_name, column_name, options) - .and_return(index_options) - ) + before do + allow(adapter).to( + receive(:add_index_options) + .with(table_name, column_name, options) + .and_return(index_options) + ) + end + + it 'passes the built SQL to #execute' do + expect(adapter).to receive(:execute).with(expected_sql) + adapter.add_index(table_name, column_name, options) + end end - it 'passes the built SQL to #execute' do - expect(adapter).to receive(:execute).with(expected_sql) - adapter.add_index(table_name, column_name, options) + describe '#remove_index' do + let(:table_name) { :foo } + let(:options) { { column: :bar_id } } + let(:sql) { 'DROP INDEX `index_name`' } + + before do + allow(adapter).to( + receive(:index_name_for_remove) + .with(table_name, options) + .and_return('index_name') + ) + allow(adapter).to( + receive(:index_name_for_remove) + .with(table_name, nil, options) + .and_return('index_name') + ) + end + + it 'passes the built SQL to #execute' do + expect(adapter).to( + receive(:execute) + .with("ALTER TABLE `#{table_name}` DROP INDEX `index_name`") + ) + adapter.remove_index(table_name, **options) + end end end - describe '#remove_index' do - let(:table_name) { :foo } - let(:options) { { column: :bar_id } } - let(:sql) { 'DROP INDEX `index_name`' } + describe '#exec_delete' do + let(:sql) { 'DELETE FROM comments WHERE id = 1' } + let(:affected_rows) { 1 } + let(:name) { nil } + let(:binds) { nil } before do - allow(adapter).to( - receive(:index_name_for_remove) - .with(table_name, options) - .and_return('index_name') - ) - allow(adapter).to( - receive(:index_name_for_remove) - .with(table_name, nil, options) - .and_return('index_name') - ) + allow(runner).to receive(:query).with(anything) + allow(mysql_client).to receive(:affected_rows).and_return(affected_rows) end - it 'passes the built SQL to #execute' do - expect(adapter).to( - receive(:execute) - .with("ALTER TABLE `#{table_name}` DROP INDEX `index_name`") - ) - adapter.remove_index(table_name, **options) + it 'executes the sql' do + expect(adapter).to(receive(:execute).with(sql, name)) + adapter.exec_delete(sql, name, binds) end - end - end - - describe '#exec_delete' do - let(:sql) { 'DELETE FROM comments WHERE id = 1' } - let(:affected_rows) { 1 } - let(:name) { nil } - let(:binds) { nil } - before do - allow(runner).to receive(:query).with(anything) - allow(mysql_client).to receive(:affected_rows).and_return(affected_rows) + it 'returns the number of affected rows' do + expect(adapter.exec_delete(sql, name, binds)).to eq(affected_rows) + end end - it 'executes the sql' do - expect(adapter).to(receive(:execute).with(sql, name)) - adapter.exec_delete(sql, name, binds) - end + describe '#exec_insert' do + let(:sql) { 'INSERT INTO comments (id) VALUES (20)' } + let(:name) { nil } + let(:binds) { nil } - it 'returns the number of affected rows' do - expect(adapter.exec_delete(sql, name, binds)).to eq(affected_rows) + it 'executes the sql' do + expect(subject).to(receive(:execute).with(sql, name)) + subject.exec_insert(sql, name, binds) + end end - end - - describe '#exec_insert' do - let(:sql) { 'INSERT INTO comments (id) VALUES (20)' } - let(:name) { nil } - let(:binds) { nil } - it 'executes the sql' do - expect(adapter).to(receive(:execute).with(sql, name)) - adapter.exec_insert(sql, name, binds) - end - end + describe '#exec_query' do + let(:sql) { 'SELECT * FROM comments' } + let(:name) { nil } + let(:binds) { nil } - describe '#exec_query' do - let(:sql) { 'SELECT * FROM comments' } - let(:name) { nil } - let(:binds) { nil } + before do + allow(runner).to receive(:query).with(sql) + allow(subject).to( + receive(:execute).with(sql, name).and_return(result_set) + ) + end - before do - allow(runner).to receive(:query).with(sql) - allow(adapter).to( - receive(:execute).with(sql, name).and_return(result_set) - ) - end + context 'when the adapter returns results' do + let(:result_set) { double(fields: [:id], to_a: [1]) } - context 'when the adapter returns results' do - let(:result_set) { double(fields: [:id], to_a: [1]) } + it 'executes the sql' do + expect(adapter).to( + receive(:execute).with(sql, name) + ).and_return(result_set) - it 'executes the sql' do - expect(adapter).to( - receive(:execute).with(sql, name) - ).and_return(result_set) + adapter.exec_query(sql, name, binds) + end - adapter.exec_query(sql, name, binds) + it 'returns an ActiveRecord::Result' do + expect(ActiveRecord::Result).to( + receive(:new).with(result_set.fields, result_set.to_a) + ) + adapter.exec_query(sql, name, binds) + end end - it 'returns an ActiveRecord::Result' do - expect(ActiveRecord::Result).to( - receive(:new).with(result_set.fields, result_set.to_a) - ) - adapter.exec_query(sql, name, binds) - end - end + context 'when the adapter returns nil' do + let(:result_set) { nil } - context 'when the adapter returns nil' do - let(:result_set) { nil } + it 'executes the sql' do + expect(adapter).to( + receive(:execute).with(sql, name) + ).and_return(result_set) - it 'executes the sql' do - expect(adapter).to( - receive(:execute).with(sql, name) - ).and_return(result_set) + adapter.exec_query(sql, name, binds) + end - adapter.exec_query(sql, name, binds) + it 'returns an ActiveRecord::Result' do + expect(ActiveRecord::Result).to( + receive(:new).with(nil, []) + ) + adapter.exec_query(sql, name, binds) + end end + end + + describe '#last_inserted_id' do + let(:result) { double(:result) } - it 'returns an ActiveRecord::Result' do - expect(ActiveRecord::Result).to( - receive(:new).with(nil, []) + it 'delegates to the mysql adapter' do + expect(mysql_adapter).to( + receive(:last_inserted_id).with(result) ) - adapter.exec_query(sql, name, binds) + adapter.last_inserted_id(result) end end - end - describe '#last_inserted_id' do - let(:result) { double(:result) } + describe '#select_rows' do + subject { adapter.select_rows(sql, name) } - it 'delegates to the mysql adapter' do - expect(mysql_adapter).to( - receive(:last_inserted_id).with(result) - ) - adapter.last_inserted_id(result) - end - end + let(:sql) { 'SELECT id, body FROM comments' } + let(:name) { nil } - describe '#select_rows' do - subject { adapter.select_rows(sql, name) } + let(:array_of_rows) { [%w[1 body], %w[2 body]] } + let(:mysql_result) do + instance_double(result_class, to_a: array_of_rows, fields: [:id, :body]) + end - let(:sql) { 'SELECT id, body FROM comments' } - let(:name) { nil } + before do + allow(adapter).to( + receive(:execute).with(sql, name) + ).and_return(mysql_result) + end - let(:array_of_rows) { [%w[1 body], %w[2 body]] } - let(:mysql2_result) do - instance_double(Mysql2::Result, to_a: array_of_rows, fields: [:id, :body]) + it { is_expected.to match_array(array_of_rows) } end - before do - allow(adapter).to( - receive(:execute).with(sql, name) - ).and_return(mysql2_result) - end + describe '#select' do + subject { adapter.select(sql, name) } - it { is_expected.to match_array(array_of_rows) } - end + let(:sql) { 'SELECT id, body FROM comments' } + let(:name) { nil } - describe '#select' do - subject { adapter.select(sql, name) } + let(:array_of_rows) { [%w[1 body], %w[2 body]] } + let(:mysql_result) do + instance_double(result_class, fields: %w[id body], to_a: array_of_rows) + end - let(:sql) { 'SELECT id, body FROM comments' } - let(:name) { nil } + before do + allow(adapter).to( + receive(:execute).with(sql, name) + ).and_return(mysql_result) + end - let(:array_of_rows) { [%w[1 body], %w[2 body]] } - let(:mysql2_result) do - instance_double(Mysql2::Result, fields: %w[id body], to_a: array_of_rows) + it do + is_expected.to match_array( + [ + { 'id' => '1', 'body' => 'body' }, + { 'id' => '2', 'body' => 'body' } + ] + ) + end end + end - before do - allow(adapter).to( - receive(:execute).with(sql, name) - ).and_return(mysql2_result) - end + context "with a Mysql2Adapter backend" do + it_behaves_like ActiveRecord::ConnectionAdapters::DepartureAdapter, + ActiveRecord::ConnectionAdapters::Mysql2Adapter, + Mysql2::Result + end - it do - is_expected.to match_array( - [ - { 'id' => '1', 'body' => 'body' }, - { 'id' => '2', 'body' => 'body' } - ] - ) - end + context "with a TrilogyAdapter backend" do + it_behaves_like ActiveRecord::ConnectionAdapters::DepartureAdapter, + ActiveRecord::ConnectionAdapters::TrilogyAdapter, + Trilogy::Result end end