lhm-shopify 3.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +34 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +183 -0
- data/.travis.yml +21 -0
- data/CHANGELOG.md +216 -0
- data/Gemfile +5 -0
- data/LICENSE +27 -0
- data/README.md +284 -0
- data/Rakefile +22 -0
- data/bin/.gitkeep +0 -0
- data/dbdeployer/config.json +32 -0
- data/dbdeployer/install.sh +64 -0
- data/dev.yml +20 -0
- data/gemfiles/ar-2.3_mysql.gemfile +6 -0
- data/gemfiles/ar-3.2_mysql.gemfile +5 -0
- data/gemfiles/ar-3.2_mysql2.gemfile +5 -0
- data/gemfiles/ar-4.0_mysql2.gemfile +5 -0
- data/gemfiles/ar-4.1_mysql2.gemfile +5 -0
- data/gemfiles/ar-4.2_mysql2.gemfile +5 -0
- data/gemfiles/ar-5.0_mysql2.gemfile +5 -0
- data/lhm.gemspec +34 -0
- data/lib/lhm.rb +131 -0
- data/lib/lhm/atomic_switcher.rb +52 -0
- data/lib/lhm/chunk_finder.rb +32 -0
- data/lib/lhm/chunk_insert.rb +51 -0
- data/lib/lhm/chunker.rb +87 -0
- data/lib/lhm/cleanup/current.rb +74 -0
- data/lib/lhm/command.rb +48 -0
- data/lib/lhm/entangler.rb +117 -0
- data/lib/lhm/intersection.rb +51 -0
- data/lib/lhm/invoker.rb +98 -0
- data/lib/lhm/locked_switcher.rb +74 -0
- data/lib/lhm/migration.rb +43 -0
- data/lib/lhm/migrator.rb +237 -0
- data/lib/lhm/printer.rb +59 -0
- data/lib/lhm/railtie.rb +9 -0
- data/lib/lhm/sql_helper.rb +77 -0
- data/lib/lhm/sql_retry.rb +61 -0
- data/lib/lhm/table.rb +121 -0
- data/lib/lhm/table_name.rb +23 -0
- data/lib/lhm/test_support.rb +35 -0
- data/lib/lhm/throttler.rb +36 -0
- data/lib/lhm/throttler/slave_lag.rb +145 -0
- data/lib/lhm/throttler/threads_running.rb +53 -0
- data/lib/lhm/throttler/time.rb +29 -0
- data/lib/lhm/timestamp.rb +11 -0
- data/lib/lhm/version.rb +6 -0
- data/shipit.rubygems.yml +0 -0
- data/spec/.lhm.example +4 -0
- data/spec/README.md +58 -0
- data/spec/fixtures/bigint_table.ddl +4 -0
- data/spec/fixtures/composite_primary_key.ddl +7 -0
- data/spec/fixtures/custom_primary_key.ddl +6 -0
- data/spec/fixtures/destination.ddl +6 -0
- data/spec/fixtures/lines.ddl +7 -0
- data/spec/fixtures/origin.ddl +6 -0
- data/spec/fixtures/permissions.ddl +5 -0
- data/spec/fixtures/small_table.ddl +4 -0
- data/spec/fixtures/tracks.ddl +5 -0
- data/spec/fixtures/users.ddl +14 -0
- data/spec/fixtures/wo_id_int_column.ddl +6 -0
- data/spec/integration/atomic_switcher_spec.rb +93 -0
- data/spec/integration/chunk_insert_spec.rb +29 -0
- data/spec/integration/chunker_spec.rb +185 -0
- data/spec/integration/cleanup_spec.rb +136 -0
- data/spec/integration/entangler_spec.rb +66 -0
- data/spec/integration/integration_helper.rb +237 -0
- data/spec/integration/invoker_spec.rb +33 -0
- data/spec/integration/lhm_spec.rb +585 -0
- data/spec/integration/lock_wait_timeout_spec.rb +30 -0
- data/spec/integration/locked_switcher_spec.rb +50 -0
- data/spec/integration/sql_retry/lock_wait_spec.rb +125 -0
- data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +101 -0
- data/spec/integration/table_spec.rb +91 -0
- data/spec/test_helper.rb +32 -0
- data/spec/unit/atomic_switcher_spec.rb +31 -0
- data/spec/unit/chunk_finder_spec.rb +73 -0
- data/spec/unit/chunk_insert_spec.rb +44 -0
- data/spec/unit/chunker_spec.rb +166 -0
- data/spec/unit/entangler_spec.rb +124 -0
- data/spec/unit/intersection_spec.rb +51 -0
- data/spec/unit/lhm_spec.rb +29 -0
- data/spec/unit/locked_switcher_spec.rb +51 -0
- data/spec/unit/migrator_spec.rb +146 -0
- data/spec/unit/printer_spec.rb +97 -0
- data/spec/unit/sql_helper_spec.rb +32 -0
- data/spec/unit/table_name_spec.rb +39 -0
- data/spec/unit/table_spec.rb +47 -0
- data/spec/unit/throttler/slave_lag_spec.rb +317 -0
- data/spec/unit/throttler/threads_running_spec.rb +64 -0
- data/spec/unit/throttler_spec.rb +124 -0
- data/spec/unit/unit_helper.rb +13 -0
- metadata +239 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
# Copyright (c) 2011 - 2013, SoundCloud Ltd., Rany Keddo, Tobias Bielohlawek, Tobias
|
2
|
+
# Schmidt
|
3
|
+
|
4
|
+
require File.expand_path(File.dirname(__FILE__)) + '/integration_helper'
|
5
|
+
|
6
|
+
describe Lhm, 'cleanup' do
|
7
|
+
include IntegrationHelper
|
8
|
+
before(:each) { connect_master! }
|
9
|
+
|
10
|
+
describe 'changes' do
|
11
|
+
before(:each) do
|
12
|
+
table_create(:users)
|
13
|
+
table_create(:permissions)
|
14
|
+
simulate_failed_migration do
|
15
|
+
Lhm.change_table(:users, :atomic_switch => false) do |t|
|
16
|
+
t.add_column(:logins, "INT(12) DEFAULT '0'")
|
17
|
+
t.add_index(:logins)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
simulate_failed_migration do
|
21
|
+
Lhm.change_table(:permissions, :atomic_switch => false) do |t|
|
22
|
+
t.add_column(:user_id, "INT(12) DEFAULT '0'")
|
23
|
+
t.add_index(:user_id)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:each) do
|
29
|
+
Lhm.cleanup(true)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'cleanup' do
|
33
|
+
it 'should show temporary tables' do
|
34
|
+
output = capture_stdout do
|
35
|
+
Lhm.cleanup
|
36
|
+
end
|
37
|
+
output.must_include('Would drop LHM backup tables')
|
38
|
+
output.must_match(/lhma_[0-9_]*_users/)
|
39
|
+
output.must_match(/lhma_[0-9_]*_permissions/)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should show temporary tables within range' do
|
43
|
+
table = OpenStruct.new(:name => 'users')
|
44
|
+
table_name = Lhm::Migration.new(table, nil, nil, {}, Time.now - 172800).archive_name
|
45
|
+
table_rename(:users, table_name)
|
46
|
+
|
47
|
+
table2 = OpenStruct.new(:name => 'permissions')
|
48
|
+
table_name2 = Lhm::Migration.new(table2, nil, nil, {}, Time.now - 172800).archive_name
|
49
|
+
table_rename(:permissions, table_name2)
|
50
|
+
|
51
|
+
output = capture_stdout do
|
52
|
+
Lhm.cleanup false, { :until => Time.now - 86400 }
|
53
|
+
end
|
54
|
+
output.must_include('Would drop LHM backup tables')
|
55
|
+
output.must_match(/lhma_[0-9_]*_users/)
|
56
|
+
output.must_match(/lhma_[0-9_]*_permissions/)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should exclude temporary tables outside range' do
|
60
|
+
table = OpenStruct.new(:name => 'users')
|
61
|
+
table_name = Lhm::Migration.new(table, nil, nil, {}, Time.now).archive_name
|
62
|
+
table_rename(:users, table_name)
|
63
|
+
|
64
|
+
table2 = OpenStruct.new(:name => 'permissions')
|
65
|
+
table_name2 = Lhm::Migration.new(table2, nil, nil, {}, Time.now).archive_name
|
66
|
+
table_rename(:permissions, table_name2)
|
67
|
+
|
68
|
+
output = capture_stdout do
|
69
|
+
Lhm.cleanup false, { :until => Time.now - 172800 }
|
70
|
+
end
|
71
|
+
output.must_include('Would drop LHM backup tables')
|
72
|
+
output.wont_match(/lhma_[0-9_]*_users/)
|
73
|
+
output.wont_match(/lhma_[0-9_]*_permissions/)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should show temporary triggers' do
|
77
|
+
output = capture_stdout do
|
78
|
+
Lhm.cleanup
|
79
|
+
end
|
80
|
+
output.must_include('Would drop LHM triggers')
|
81
|
+
output.must_include('lhmt_ins_users')
|
82
|
+
output.must_include('lhmt_del_users')
|
83
|
+
output.must_include('lhmt_upd_users')
|
84
|
+
output.must_include('lhmt_ins_permissions')
|
85
|
+
output.must_include('lhmt_del_permissions')
|
86
|
+
output.must_include('lhmt_upd_permissions')
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should delete temporary tables' do
|
90
|
+
Lhm.cleanup(true).must_equal(true)
|
91
|
+
Lhm.cleanup.must_equal(true)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'cleanup_current_run' do
|
96
|
+
it 'should show lhmn table for the specified table only' do
|
97
|
+
table_create(:permissions)
|
98
|
+
table_rename(:permissions, 'lhmn_permissions')
|
99
|
+
output = capture_stdout do
|
100
|
+
Lhm.cleanup_current_run(false, 'permissions')
|
101
|
+
end.split("\n")
|
102
|
+
|
103
|
+
assert_equal "The following DDLs would be executed:", output[0]
|
104
|
+
assert_equal "drop trigger if exists lhmt_ins_permissions", output[1]
|
105
|
+
assert_equal "drop trigger if exists lhmt_upd_permissions", output[2]
|
106
|
+
assert_equal "drop trigger if exists lhmt_del_permissions", output[3]
|
107
|
+
assert_match(/rename table lhmn_permissions to lhma_[0-9_]*_permissions_failed/, output[4])
|
108
|
+
assert_equal 5, output.length
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should show temporary triggers for the specified table only' do
|
112
|
+
output = capture_stdout do
|
113
|
+
Lhm.cleanup_current_run(false, 'permissions')
|
114
|
+
end.split("\n")
|
115
|
+
assert_equal "The following DDLs would be executed:", output[0]
|
116
|
+
assert_equal "drop trigger if exists lhmt_ins_permissions", output[1]
|
117
|
+
assert_equal "drop trigger if exists lhmt_upd_permissions", output[2]
|
118
|
+
assert_equal "drop trigger if exists lhmt_del_permissions", output[3]
|
119
|
+
assert_equal 4, output.length
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should delete temporary tables and triggers for the specified table only' do
|
123
|
+
assert Lhm.cleanup_current_run(true, 'permissions')
|
124
|
+
|
125
|
+
all_tables = Lhm.connection.select_values('show tables')
|
126
|
+
all_triggers = Lhm.connection.select_values('show triggers')
|
127
|
+
|
128
|
+
refute all_tables.include?('lhmn_permissions')
|
129
|
+
assert all_tables.find { |t| t =~ /lhma_(.*)_users/}
|
130
|
+
|
131
|
+
refute all_triggers.find { |t| t =~ /lhmt_(.*)_permissions/}
|
132
|
+
assert all_triggers.find { |t| t =~ /lhmt_(.*)_users/}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright (c) 2011 - 2013, SoundCloud Ltd., Rany Keddo, Tobias Bielohlawek, Tobias
|
2
|
+
# Schmidt
|
3
|
+
|
4
|
+
require File.expand_path(File.dirname(__FILE__)) + '/integration_helper'
|
5
|
+
|
6
|
+
require 'lhm/table'
|
7
|
+
require 'lhm/migration'
|
8
|
+
require 'lhm/entangler'
|
9
|
+
|
10
|
+
describe Lhm::Entangler do
|
11
|
+
include IntegrationHelper
|
12
|
+
|
13
|
+
before(:each) { connect_master! }
|
14
|
+
|
15
|
+
describe 'entanglement' do
|
16
|
+
before(:each) do
|
17
|
+
@origin = table_create('origin')
|
18
|
+
@destination = table_create('destination')
|
19
|
+
@migration = Lhm::Migration.new(@origin, @destination)
|
20
|
+
@entangler = Lhm::Entangler.new(@migration, connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should replay inserts from origin into destination' do
|
24
|
+
@entangler.run do
|
25
|
+
execute("insert into origin (common) values ('inserted')")
|
26
|
+
end
|
27
|
+
|
28
|
+
slave do
|
29
|
+
count(:destination, 'common', 'inserted').must_equal(1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should replay deletes from origin into destination' do
|
34
|
+
execute("insert into origin (common) values ('inserted')")
|
35
|
+
|
36
|
+
@entangler.run do
|
37
|
+
execute("delete from origin where common = 'inserted'")
|
38
|
+
end
|
39
|
+
|
40
|
+
slave do
|
41
|
+
count(:destination, 'common', 'inserted').must_equal(0)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should replay updates from origin into destination' do
|
46
|
+
@entangler.run do
|
47
|
+
execute("insert into origin (common) values ('inserted')")
|
48
|
+
execute("update origin set common = 'updated'")
|
49
|
+
end
|
50
|
+
|
51
|
+
slave do
|
52
|
+
count(:destination, 'common', 'updated').must_equal(1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should remove entanglement' do
|
57
|
+
@entangler.run {}
|
58
|
+
|
59
|
+
execute("insert into origin (common) values ('inserted')")
|
60
|
+
|
61
|
+
slave do
|
62
|
+
count(:destination, 'common', 'inserted').must_equal(0)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# Copyright (c) 2011 - 2013, SoundCloud Ltd., Rany Keddo, Tobias Bielohlawek, Tobias
|
2
|
+
# Schmidt
|
3
|
+
require 'test_helper'
|
4
|
+
require 'yaml'
|
5
|
+
require 'active_support'
|
6
|
+
|
7
|
+
begin
|
8
|
+
$db_config = YAML.load_file(File.expand_path(File.dirname(__FILE__)) + '/database.yml')
|
9
|
+
rescue StandardError => e
|
10
|
+
puts "Run install.sh to setup database"
|
11
|
+
raise e
|
12
|
+
end
|
13
|
+
|
14
|
+
$db_name = 'test'
|
15
|
+
|
16
|
+
require 'lhm/table'
|
17
|
+
require 'lhm/sql_helper'
|
18
|
+
|
19
|
+
module IntegrationHelper
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.after(:each) do
|
23
|
+
cleanup_connection = new_mysql_connection
|
24
|
+
results = cleanup_connection.query("SELECT table_name FROM information_schema.tables WHERE table_schema = '#{$db_name}';")
|
25
|
+
table_names_for_cleanup = results.map { |row| "#{$db_name}." + row.values.first }
|
26
|
+
cleanup_connection.query("DROP TABLE IF EXISTS #{table_names_for_cleanup.join(', ')};") if table_names_for_cleanup.length > 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Connectivity
|
32
|
+
#
|
33
|
+
def connection
|
34
|
+
@connection
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect_master!
|
38
|
+
connect!(
|
39
|
+
'127.0.0.1',
|
40
|
+
$db_config['master']['port'],
|
41
|
+
$db_config['master']['user'],
|
42
|
+
$db_config['master']['password'],
|
43
|
+
$db_config['master']['socket']
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def connect_slave!
|
48
|
+
connect!(
|
49
|
+
'127.0.0.1',
|
50
|
+
$db_config['slave']['port'],
|
51
|
+
$db_config['slave']['user'],
|
52
|
+
$db_config['slave']['password'],
|
53
|
+
$db_config['slave']['socket']
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def connect!(hostname, port, user, password, socket)
|
58
|
+
adapter = ar_conn(hostname, port, user, password, socket)
|
59
|
+
Lhm.setup(adapter)
|
60
|
+
unless defined?(@@cleaned_up)
|
61
|
+
Lhm.cleanup(true)
|
62
|
+
@@cleaned_up = true
|
63
|
+
end
|
64
|
+
@connection = adapter
|
65
|
+
end
|
66
|
+
|
67
|
+
def ar_conn(host, port, user, password, socket)
|
68
|
+
ActiveRecord::Base.establish_connection(
|
69
|
+
:adapter => 'mysql2',
|
70
|
+
:host => host,
|
71
|
+
:username => user,
|
72
|
+
:port => port,
|
73
|
+
:password => password,
|
74
|
+
:socket => socket,
|
75
|
+
:database => $db_name
|
76
|
+
)
|
77
|
+
ActiveRecord::Base.connection
|
78
|
+
end
|
79
|
+
|
80
|
+
def select_one(*args)
|
81
|
+
@connection.select_one(*args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def select_value(*args)
|
85
|
+
@connection.select_value(*args)
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute(*args)
|
89
|
+
retries = 10
|
90
|
+
begin
|
91
|
+
@connection.execute(*args)
|
92
|
+
rescue => e
|
93
|
+
if (retries -= 1) > 0 && e.message =~ /Table '.*?' doesn't exist/
|
94
|
+
sleep 0.1
|
95
|
+
retry
|
96
|
+
else
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def slave(&block)
|
103
|
+
if master_slave_mode?
|
104
|
+
connect_slave!
|
105
|
+
|
106
|
+
# need to wait for the slave to catch up. a better method would be to
|
107
|
+
# check the master binlog position and wait for the slave to catch up
|
108
|
+
# to that position.
|
109
|
+
sleep 1
|
110
|
+
else
|
111
|
+
connect_master!
|
112
|
+
end
|
113
|
+
|
114
|
+
yield block
|
115
|
+
|
116
|
+
if master_slave_mode?
|
117
|
+
connect_master!
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Helps testing behaviour when another client locks the db
|
122
|
+
def start_locking_thread(lock_for, queue, locking_query)
|
123
|
+
Thread.new do
|
124
|
+
conn = Mysql2::Client.new(host: '127.0.0.1', database: $db_name, user: 'root', port: 3306)
|
125
|
+
conn.query('BEGIN')
|
126
|
+
conn.query(locking_query)
|
127
|
+
queue.push(true)
|
128
|
+
sleep(lock_for) # Sleep for log so LHM gives up
|
129
|
+
conn.query('ROLLBACK')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Test Data
|
135
|
+
#
|
136
|
+
|
137
|
+
def fixture(name)
|
138
|
+
File.read($fixtures.join("#{ name }.ddl"))
|
139
|
+
end
|
140
|
+
|
141
|
+
def table_create(fixture_name)
|
142
|
+
execute "drop table if exists `#{ fixture_name }`"
|
143
|
+
execute fixture(fixture_name)
|
144
|
+
table_read(fixture_name)
|
145
|
+
end
|
146
|
+
|
147
|
+
def table_rename(from_name, to_name)
|
148
|
+
execute "rename table `#{ from_name }` to `#{ to_name }`"
|
149
|
+
end
|
150
|
+
|
151
|
+
def table_read(fixture_name)
|
152
|
+
Lhm::Table.parse(fixture_name, @connection)
|
153
|
+
end
|
154
|
+
|
155
|
+
def data_source_exists?(table)
|
156
|
+
connection.data_source_exists?(table.name)
|
157
|
+
end
|
158
|
+
|
159
|
+
def new_mysql_connection(role='master')
|
160
|
+
Mysql2::Client.new(
|
161
|
+
host: '127.0.0.1',
|
162
|
+
database: $db_name,
|
163
|
+
username: $db_config[role]['user'],
|
164
|
+
password: $db_config[role]['password'],
|
165
|
+
port: $db_config[role]['port'],
|
166
|
+
socket: $db_config[role]['socket']
|
167
|
+
)
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Database Helpers
|
172
|
+
#
|
173
|
+
|
174
|
+
def count(table, column, value)
|
175
|
+
query = "select count(*) from #{ table } where #{ column } = '#{ value }'"
|
176
|
+
select_value(query).to_i
|
177
|
+
end
|
178
|
+
|
179
|
+
def count_all(table)
|
180
|
+
query = "select count(*) from `#{ table }`"
|
181
|
+
select_value(query).to_i
|
182
|
+
end
|
183
|
+
|
184
|
+
def index_on_columns?(table_name, cols, type = :non_unique)
|
185
|
+
key_name = Lhm::SqlHelper.idx_name(table_name, cols)
|
186
|
+
|
187
|
+
index?(table_name, key_name, type)
|
188
|
+
end
|
189
|
+
|
190
|
+
def index?(table_name, key_name, type = :non_unique)
|
191
|
+
non_unique = type == :non_unique ? 1 : 0
|
192
|
+
|
193
|
+
!!select_one(%Q<
|
194
|
+
show indexes in `#{ table_name }`
|
195
|
+
where key_name = '#{ key_name }'
|
196
|
+
and non_unique = #{ non_unique }
|
197
|
+
>)
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# Environment
|
202
|
+
#
|
203
|
+
|
204
|
+
def master_slave_mode?
|
205
|
+
!!ENV['MASTER_SLAVE']
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Misc
|
210
|
+
#
|
211
|
+
|
212
|
+
def capture_stdout
|
213
|
+
out = StringIO.new
|
214
|
+
$stdout = out
|
215
|
+
yield
|
216
|
+
return out.string
|
217
|
+
ensure
|
218
|
+
$stdout = ::STDOUT
|
219
|
+
end
|
220
|
+
|
221
|
+
def simulate_failed_migration
|
222
|
+
Lhm::Entangler.class_eval do
|
223
|
+
alias_method :old_after, :after
|
224
|
+
def after
|
225
|
+
true
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
yield
|
230
|
+
ensure
|
231
|
+
Lhm::Entangler.class_eval do
|
232
|
+
undef_method :after
|
233
|
+
alias_method :after, :old_after
|
234
|
+
undef_method :old_after
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/integration_helper'
|
2
|
+
|
3
|
+
require 'lhm/invoker'
|
4
|
+
|
5
|
+
describe Lhm::Invoker do
|
6
|
+
include IntegrationHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
connect_master!
|
10
|
+
@origin = table_create('users')
|
11
|
+
@destination = table_create('destination')
|
12
|
+
@invoker = Lhm::Invoker.new(Lhm::Table.parse(:users, @connection), @connection)
|
13
|
+
@migration = Lhm::Migration.new(@origin, @destination)
|
14
|
+
@entangler = Lhm::Entangler.new(@migration, @connection)
|
15
|
+
@entangler.before
|
16
|
+
end
|
17
|
+
|
18
|
+
after(:each) do
|
19
|
+
@entangler.after if @invoker.triggers_still_exist?(@invoker.connection, @entangler)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'triggers_still_exist?' do
|
23
|
+
it 'should return true when triggers still exist' do
|
24
|
+
assert @invoker.triggers_still_exist?(@invoker.connection, @entangler)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return false when triggers do not exist' do
|
28
|
+
@entangler.after
|
29
|
+
|
30
|
+
refute @invoker.triggers_still_exist?(@invoker.connection, @entangler)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|