Skip to content

test: stub connection in unit test to emulate multi adapter support within the same suite #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,34 @@ matrix:
include:
- rvm: 2.2
gemfile: gemfiles/rails_3.gemfile
env: DB_ADAPTER=sqlite
- rvm: 2.2
gemfile: gemfiles/rails_3.gemfile
env: DB_ADAPTER=mysql
- rvm: 2.2
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=sqlite
- rvm: 2.2
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=mysql
- rvm: 2.3
gemfile: gemfiles/rails_3.gemfile
env: DB_ADAPTER=sqlite
- rvm: 2.3
gemfile: gemfiles/rails_3.gemfile
env: DB_ADAPTER=mysql
- rvm: 2.3
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=sqlite
- rvm: 2.3
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=mysql
- rvm: 2.4
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=sqlite
- rvm: 2.4
gemfile: gemfiles/rails_4.gemfile
env: DB_ADAPTER=mysql
exclude:
- rvm: 2.3
gemfile: gemfiles/rails_6.gemfile
Expand Down
129 changes: 91 additions & 38 deletions test/bulk_insert/worker_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,9 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
assert_equal @insert.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end

test "adapter dependent mysql methods" do
test "adapter dependent MySQL methods" do
connection = Testing.connection
connection.stub :adapter_name, 'MySQL' do
stub_connection_if_needed(connection, 'mysql') do
mysql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -282,20 +282,21 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
true # ignore
)

assert_equal mysql_worker.adapter_name, 'MySQL'
assert_equal (mysql_worker.adapter_name == 'MySQL'), true
assert_equal mysql_worker.adapter_name, 'mysql'
assert_equal (mysql_worker.adapter_name == 'mysql'), true
assert_equal mysql_worker.ignore, true
assert_equal ((mysql_worker.adapter_name == 'MySQL') & mysql_worker.ignore), true
assert_equal ((mysql_worker.adapter_name == 'mysql') & mysql_worker.ignore), true

mysql_worker.add ["Yo", 15, false, nil, nil]

assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end
end

test "adapter dependent mysql methods work for mysql2" do
connection = Testing.connection
connection.stub :adapter_name, 'Mysql2' do
stub_connection_if_needed(connection, 'mysql2') do
mysql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -305,18 +306,19 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
true, # ignore
true) # update_duplicates

assert_equal mysql_worker.adapter_name, 'Mysql2'
assert_equal mysql_worker.adapter_name, 'mysql2'
assert mysql_worker.ignore

mysql_worker.add ["Yo", 15, false, nil, nil]

assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
end
end

test "adapter dependent Mysql2Spatial methods" do
connection = Testing.connection
connection.stub :adapter_name, 'Mysql2Spatial' do
stub_connection_if_needed(connection, 'mysql2spatial') do
mysql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -325,17 +327,18 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
500, # batch size
true) # ignore

assert_equal mysql_worker.adapter_name, 'Mysql2Spatial'
assert_equal mysql_worker.adapter_name, 'mysql2spatial'

mysql_worker.add ["Yo", 15, false, nil, nil]

assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end
end

test "adapter dependent postgresql methods" do
connection = Testing.connection
connection.stub :adapter_name, 'PostgreSQL' do
stub_connection_if_needed(connection, 'PostgreSQL') do
pgsql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -349,13 +352,14 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase

pgsql_worker.add ["Yo", 15, false, nil, nil]

assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
end
end

test "adapter dependent postgresql methods (no ignore, no update_duplicates)" do
connection = Testing.connection
connection.stub :adapter_name, 'PostgreSQL' do
stub_connection_if_needed(connection, 'PostgreSQL') do
pgsql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -369,13 +373,14 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase

pgsql_worker.add ["Yo", 15, false, nil, nil]

assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') RETURNING id"
end
end

test "adapter dependent postgresql methods (with update_duplicates)" do
connection = Testing.connection
connection.stub :adapter_name, 'PostgreSQL' do
stub_connection_if_needed(connection, 'PostgreSQL') do
pgsql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -388,13 +393,14 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
)
pgsql_worker.add ["Yo", 15, false, nil, nil]

assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON CONFLICT(greeting, age, happy) DO UPDATE SET greeting=EXCLUDED.greeting, age=EXCLUDED.age, happy=EXCLUDED.happy, created_at=EXCLUDED.created_at, updated_at=EXCLUDED.updated_at, color=EXCLUDED.color RETURNING id"
end
end

test "adapter dependent PostGIS methods" do
connection = Testing.connection
connection.stub :adapter_name, 'PostGIS' do
stub_connection_if_needed(connection, 'postgis') do
pgsql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -407,41 +413,50 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
)
pgsql_worker.add ["Yo", 15, false, nil, nil]

assert_statement_adapter pgsql_worker, 'BulkInsert::StatementAdapters::PostgreSQLAdapter'
assert_equal pgsql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON CONFLICT DO NOTHING RETURNING id"
end
end

test "adapter dependent sqlite3 methods (with lowercase adapter name)" do
sqlite_worker = BulkInsert::Worker.new(
Testing.connection,
Testing.table_name,
'id',
%w(greeting age happy created_at updated_at color),
500, # batch size
true) # ignore
sqlite_worker.adapter_name = 'sqlite3'
sqlite_worker.add ["Yo", 15, false, nil, nil]
connection = Testing.connection
stub_connection_if_needed(connection, 'sqlite3') do
sqlite_worker = BulkInsert::Worker.new(
Testing.connection,
Testing.table_name,
'id',
%w(greeting age happy created_at updated_at color),
500, # batch size
true) # ignore
sqlite_worker.adapter_name = 'sqlite3'
sqlite_worker.add ["Yo", 15, false, nil, nil]

assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
assert_statement_adapter sqlite_worker, 'BulkInsert::StatementAdapters::SQLiteAdapter'
assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end
end

test "adapter dependent sqlite3 methods (with stylecase adapter name)" do
sqlite_worker = BulkInsert::Worker.new(
Testing.connection,
Testing.table_name,
'id',
%w(greeting age happy created_at updated_at color),
500, # batch size
true) # ignore
sqlite_worker.adapter_name = 'SQLite'
sqlite_worker.add ["Yo", 15, false, nil, nil]
connection = Testing.connection
stub_connection_if_needed(connection, 'SQLite') do
sqlite_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
'id',
%w(greeting age happy created_at updated_at color),
500, # batch size
true) # ignore
sqlite_worker.adapter_name = 'SQLite'
sqlite_worker.add ["Yo", 15, false, nil, nil]

assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
assert_statement_adapter sqlite_worker, 'BulkInsert::StatementAdapters::SQLiteAdapter'
assert_equal sqlite_worker.compose_insert_query, "INSERT OR IGNORE INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end
end

test "mysql adapter can update duplicates" do
connection = Testing.connection
connection.stub :adapter_name, 'MySQL' do
stub_connection_if_needed(connection, 'mysql') do
mysql_worker = BulkInsert::Worker.new(
connection,
Testing.table_name,
Expand All @@ -453,7 +468,45 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
)
mysql_worker.add ["Yo", 15, false, nil, nil]

assert_equal mysql_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
assert_statement_adapter mysql_worker, 'BulkInsert::StatementAdapters::MySQLAdapter'
assert_equal mysql_worker.compose_insert_query, "INSERT INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,0,NULL,NULL,'chartreuse') ON DUPLICATE KEY UPDATE `greeting`=VALUES(`greeting`), `age`=VALUES(`age`), `happy`=VALUES(`happy`), `created_at`=VALUES(`created_at`), `updated_at`=VALUES(`updated_at`), `color`=VALUES(`color`)"
end
end

def assert_statement_adapter(worker, adapter_name)
assert_equal worker.instance_variable_get(:@statement_adapter).class.to_s, adapter_name
end

DOUBLE_QUOTE_PROC = Proc.new do |value, *_column|
return value unless value.is_a? String
"\"#{value}\""
end

BACKTICK_QUOTE_PROC = Proc.new do |value, *_column|
return value unless value.is_a? String
'`' + value + '`'
end

def stub_connection_if_needed(connection, adapter_name)
raise "You need to provide a block" unless block_given?
if connection.adapter_name == adapter_name
yield
else
connection.stub :adapter_name, adapter_name do
if adapter_name =~ /^mysql/i
connection.stub :quote_table_name, BACKTICK_QUOTE_PROC do
connection.stub :quote_column_name, BACKTICK_QUOTE_PROC do
yield
end
end
else
connection.stub :quote_table_name, DOUBLE_QUOTE_PROC do
connection.stub :quote_column_name, DOUBLE_QUOTE_PROC do
yield
end
end
end
end
end
end
end