Sitelet https://github.com/jamis/bulk_insert/pull/77/files
Skip to content
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
73 changes: 27 additions & 46 deletions test/bulk_insert/worker_test.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
require 'minitest/mock'
require 'test_helper'
require 'connection_mocks'

class BulkInsertWorkerTest < ActiveSupport::TestCase
include ConnectionMocks

setup do
@insert = BulkInsert::Worker.new(
Testing.connection,
Testing.table_name,
'id',
%w(greeting age happy created_at updated_at color))
@now = Time.now
@now = Time.now.utc
end

test "empty insert is not pending" do
Expand Down Expand Up @@ -37,8 +40,8 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
@insert.save!

record = Testing.first
assert_operator record.created_at, :>=, now
assert_operator record.updated_at, :>=, now
assert_operator record.created_at.to_i, :>=, now.to_i
assert_operator record.updated_at.to_i, :>=, now.to_i
end

test "default timestamp columns should be equivalent for the entire batch" do
Expand Down Expand Up @@ -262,12 +265,23 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
assert_nil hello
end

test "adapter dependent default methods" do
assert_equal @insert.adapter_name, 'SQLite'
assert_equal @insert.insert_sql_statement, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES "
test "adapter dependent SQLite methods" do
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
)

assert_equal sqlite_worker.adapter_name, 'SQLite'
assert_equal sqlite_worker.insert_sql_statement, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES "

@insert.add ["Yo", 15, false, nil, nil]
assert_equal @insert.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
sqlite_worker.add ["Yo", 15, false, nil, nil]
assert_equal sqlite_worker.compose_insert_query, "INSERT INTO \"testings\" (\"greeting\",\"age\",\"happy\",\"created_at\",\"updated_at\",\"color\") VALUES ('Yo',15,0,NULL,NULL,'chartreuse')"
end
end

test "adapter dependent MySQL methods" do
Expand All @@ -290,7 +304,7 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
mysql_worker.add ["Yo", 15, false, nil, nil]

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')"
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse')"
end
end

Expand All @@ -312,7 +326,7 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
mysql_worker.add ["Yo", 15, false, nil, nil]

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`)"
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,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

Expand All @@ -332,8 +346,8 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
mysql_worker.add ["Yo", 15, false, nil, nil]

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
assert_equal mysql_worker.compose_insert_query, "INSERT IGNORE INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,NULL,NULL,'chartreuse')"
end
end

test "adapter dependent postgresql methods" do
Expand Down Expand Up @@ -469,44 +483,11 @@ class BulkInsertWorkerTest < ActiveSupport::TestCase
mysql_worker.add ["Yo", 15, false, nil, nil]

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`)"
assert_equal mysql_worker.compose_insert_query, "INSERT INTO `testings` (`greeting`,`age`,`happy`,`created_at`,`updated_at`,`color`) VALUES ('Yo',15,FALSE,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
104 changes: 104 additions & 0 deletions test/connection_mocks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
module ConnectionMocks
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

MYSQL_VALUE_QUOTE_PROC = Proc.new do |value, *_column|
case value
when String
"'" + value + "'"
when TrueClass
'TRUE'
when FalseClass
'FALSE'
when NilClass
'NULL'
else
value
end
end

DEFAULT_VALUE_QUOTE_PROC = Proc.new do |value, *_column|
case value
when String
"'" + value + "'"
when TrueClass
1
when FalseClass
0
when NilClass
'NULL'
else
value
end
end

ColumnMock = Struct.new(:name, :default)
COLUMNS_MOCK_PROC = Proc.new do |*_table_name|
%w(id greeting age happy created_at updated_at color).zip(
[nil, nil, nil, nil, nil, nil, "chartreuse"]
).map do |column_name, default|
ColumnMock.new(column_name, default)
end
end

MockTypeSerialize = Struct.new(:column) do
def serialize(value); value; end
end
CAST_COLUMN_MOCK_PROC = Proc.new do |column|
MockTypeSerialize.new(column)
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
common_mocks(connection, adapter_name) do
if adapter_name =~ /^mysql/i
mock_mysql_connection(connection, adapter_name) do
yield
end
else
connection.stub :quote_table_name, DOUBLE_QUOTE_PROC do
connection.stub :quote_column_name, DOUBLE_QUOTE_PROC do
connection.stub :quote, DEFAULT_VALUE_QUOTE_PROC do
yield
end
end
end
end
end
end
end

def common_mocks(connection, adapter_name)
connection.stub :adapter_name, adapter_name do
connection.stub :columns, COLUMNS_MOCK_PROC do
if ActiveRecord::VERSION::STRING >= "5.0.0"
connection.stub :lookup_cast_type_from_column, CAST_COLUMN_MOCK_PROC do
yield
end
else
yield
end
end
end
end

def mock_mysql_connection(connection, adapter_name)
connection.stub :quote_table_name, BACKTICK_QUOTE_PROC do
connection.stub :quote_column_name, BACKTICK_QUOTE_PROC do
connection.stub :quote, MYSQL_VALUE_QUOTE_PROC do
yield
end
end
end
end
end