lhm-shopify 3.3.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|