-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added some trivial integration tests
Just ported some very basic tests for now, looking to port more tests.
- Loading branch information
Showing
3 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require "json" | ||
require "ghostferry_integration" | ||
|
||
class TrivialIntegrationTests < GhostferryIntegration::TestCase | ||
def ghostferry_main_path | ||
"go/minimal.go" | ||
end | ||
|
||
def test_copy_data_without_any_writes_to_source | ||
@dbs.seed_simple_database_with_single_table | ||
@ghostferry.run | ||
assert_test_table_is_identical | ||
end | ||
|
||
def test_copy_data_with_writes_to_source | ||
use_datawriter | ||
|
||
@dbs.seed_simple_database_with_single_table | ||
|
||
@ghostferry.run | ||
assert_test_table_is_identical | ||
end | ||
|
||
def test_interrupt_resume_with_writes_to_source | ||
@dbs.seed_simple_database_with_single_table | ||
|
||
dumped_state = nil | ||
with_state_cleanup do | ||
use_datawriter | ||
interrupt_ghostferry_when_some_batches_are_copied | ||
|
||
dumped_state = @ghostferry.run_expecting_interrupt | ||
assert_basic_fields_exist_in_dumped_state(dumped_state) | ||
end | ||
|
||
# We want to write some data to the source database while Ghostferry is down | ||
# to verify that it is copied over. | ||
5.times do | ||
@datawriter.insert_data(@dbs.source) | ||
@datawriter.update_data(@dbs.source) | ||
@datawriter.delete_data(@dbs.source) | ||
end | ||
|
||
with_state_cleanup do | ||
use_datawriter | ||
@ghostferry.run(dumped_state) | ||
|
||
assert_test_table_is_identical | ||
end | ||
end | ||
end |
128 changes: 128 additions & 0 deletions
128
test/integration/ruby/ghostferry_integration/test_case.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
require "logger" | ||
require "minitest" | ||
require "minitest/hooks/test" | ||
|
||
module GhostferryIntegration | ||
class TestCase < Minitest::Test | ||
include Minitest::Hooks | ||
include GhostferryIntegration | ||
|
||
############## | ||
# Test Hooks # | ||
############## | ||
|
||
def before_all | ||
@logger = Logger.new(STDOUT) | ||
@logger.level = Logger::INFO | ||
@ghostferry = Ghostferry.new(ghostferry_main_path, logger: @logger) | ||
end | ||
|
||
def after_all | ||
@ghostferry.remove_binary | ||
end | ||
|
||
def before_setup | ||
@dbs = DbManager.new(logger: @logger) | ||
@dbs.reset_data | ||
|
||
@datawriter = DataWriter.new(@dbs.source_db_config, logger: @logger) | ||
end | ||
|
||
def after_teardown | ||
terminate_datawriter_and_ghostferry | ||
end | ||
|
||
###################### | ||
# Test Setup Helpers # | ||
###################### | ||
|
||
# This should be a no op if ghostferry and datawriter have already been | ||
# stopped. | ||
def terminate_datawriter_and_ghostferry | ||
@datawriter.stop | ||
@datawriter.join | ||
|
||
@ghostferry.stop_and_cleanup | ||
@datawriter = DataWriter.new(@dbs.source_db_config, logger: @logger) | ||
end | ||
|
||
# This is useful if we need to run Ghostferry multiple times in during a | ||
# single run, such as during an interrupt + resume cycle. | ||
def with_state_cleanup | ||
@datawriter = DataWriter.new(@dbs.source_db_config, logger: @logger) | ||
@ghostferry.reset_state | ||
yield | ||
terminate_datawriter_and_ghostferry | ||
end | ||
|
||
def start_datawriter_with_ghostferry(&on_write) | ||
@ghostferry.on_status(Ghostferry::Status::READY) do | ||
@datawriter.start(&on_write) | ||
end | ||
end | ||
|
||
def stop_datawriter_during_cutover | ||
@ghostferry.on_status(Ghostferry::Status::ROW_COPY_COMPLETED) do | ||
# At the start of the cutover phase, we have to set the database to | ||
# read-only. This is done by stopping the datawriter. | ||
@datawriter.stop | ||
@datawriter.join | ||
end | ||
end | ||
|
||
def use_datawriter(&on_write) | ||
start_datawriter_with_ghostferry(&on_write) | ||
stop_datawriter_during_cutover | ||
end | ||
|
||
def interrupt_ghostferry_when_some_batches_are_copied(batches: 2) | ||
batches_written = 0 | ||
@ghostferry.on_status(Ghostferry::Status::AFTER_ROW_COPY) do | ||
batches_written += 1 | ||
if batches_written >= batches | ||
@ghostferry.send_signal("TERM") | ||
end | ||
end | ||
end | ||
|
||
##################### | ||
# Assertion Helpers # | ||
##################### | ||
|
||
def assert_test_table_is_identical | ||
source, target = @dbs.source_and_target_table_metrics | ||
|
||
assert source[DbManager::DEFAULT_FULL_TABLE_NAME][:row_count] > 0 | ||
assert target[DbManager::DEFAULT_FULL_TABLE_NAME][:row_count] > 0 | ||
|
||
assert_equal( | ||
source[DbManager::DEFAULT_FULL_TABLE_NAME][:checksum], | ||
target[DbManager::DEFAULT_FULL_TABLE_NAME][:checksum], | ||
) | ||
|
||
assert_equal( | ||
source[DbManager::DEFAULT_FULL_TABLE_NAME][:sample_row], | ||
target[DbManager::DEFAULT_FULL_TABLE_NAME][:sample_row], | ||
) | ||
end | ||
|
||
# Use this method to assert the validity of the structure of the dumped | ||
# state. | ||
# | ||
# To actually assert the validity of the data within the dumped state, you | ||
# have to do it manually. | ||
def assert_basic_fields_exist_in_dumped_state(dumped_state) | ||
refute dumped_state.nil? | ||
refute dumped_state["GhostferryVersion"].nil? | ||
refute dumped_state["LastKnownTableSchemaCache"].nil? | ||
refute dumped_state["LastSuccessfulPrimaryKeys"].nil? | ||
refute dumped_state["CompletedTables"].nil? | ||
refute dumped_state["LastWrittenBinlogPosition"].nil? | ||
end | ||
|
||
protected | ||
def ghostferry_main_path | ||
raise NotImplementedError | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
require "minitest/autorun" | ||
|
||
ruby_path = File.join(File.absolute_path(File.dirname(__FILE__)), "ruby") | ||
$LOAD_PATH.unshift(ruby_path) unless $LOAD_PATH.include?(ruby_path) | ||
|
||
require_relative "cases/trivial_integration_tests" |