lhm-shopify 3.5.5 → 4.1.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +20 -18
  3. data/Appraisals +8 -19
  4. data/CHANGELOG.md +16 -0
  5. data/Gemfile.lock +37 -20
  6. data/README.md +21 -14
  7. data/dev.yml +12 -8
  8. data/docker-compose-mysql-5.7.yml +1 -0
  9. data/docker-compose-mysql-8.0.yml +63 -0
  10. data/docker-compose.yml +5 -3
  11. data/gemfiles/activerecord_6.1.gemfile +1 -0
  12. data/gemfiles/activerecord_6.1.gemfile.lock +23 -13
  13. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile → activerecord_7.0.gemfile} +2 -1
  14. data/gemfiles/{activerecord_7.0.0.alpha2.gemfile.lock → activerecord_7.0.gemfile.lock} +29 -19
  15. data/gemfiles/{activerecord_6.0.gemfile → activerecord_7.1.gemfile} +1 -1
  16. data/gemfiles/activerecord_7.1.gemfile.lock +83 -0
  17. data/lhm.gemspec +2 -1
  18. data/lib/lhm/atomic_switcher.rb +3 -3
  19. data/lib/lhm/chunker.rb +4 -4
  20. data/lib/lhm/connection.rb +9 -1
  21. data/lib/lhm/sql_helper.rb +1 -1
  22. data/lib/lhm/sql_retry.rb +36 -18
  23. data/lib/lhm/table.rb +3 -4
  24. data/lib/lhm/throttler/replica_lag.rb +166 -0
  25. data/lib/lhm/throttler/slave_lag.rb +5 -155
  26. data/lib/lhm/throttler/threads_running.rb +3 -1
  27. data/lib/lhm/throttler.rb +7 -3
  28. data/lib/lhm/version.rb +1 -1
  29. data/scripts/helpers/wait-for-dbs.sh +3 -3
  30. data/scripts/mysql/writer/create_users.sql +1 -1
  31. data/spec/.lhm.example +1 -1
  32. data/spec/README.md +8 -9
  33. data/spec/integration/atomic_switcher_spec.rb +6 -10
  34. data/spec/integration/chunk_insert_spec.rb +2 -2
  35. data/spec/integration/chunker_spec.rb +54 -44
  36. data/spec/integration/database.yml +4 -4
  37. data/spec/integration/entangler_spec.rb +4 -4
  38. data/spec/integration/integration_helper.rb +23 -15
  39. data/spec/integration/lhm_spec.rb +70 -44
  40. data/spec/integration/locked_switcher_spec.rb +2 -2
  41. data/spec/integration/proxysql_spec.rb +10 -10
  42. data/spec/integration/sql_retry/db_connection_helper.rb +2 -4
  43. data/spec/integration/sql_retry/lock_wait_spec.rb +7 -8
  44. data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +18 -10
  45. data/spec/integration/sql_retry/proxysql_helper.rb +1 -1
  46. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +1 -2
  47. data/spec/integration/table_spec.rb +1 -1
  48. data/spec/integration/toxiproxy_helper.rb +1 -1
  49. data/spec/test_helper.rb +27 -3
  50. data/spec/unit/atomic_switcher_spec.rb +2 -2
  51. data/spec/unit/chunker_spec.rb +43 -43
  52. data/spec/unit/connection_spec.rb +2 -2
  53. data/spec/unit/entangler_spec.rb +14 -24
  54. data/spec/unit/printer_spec.rb +2 -6
  55. data/spec/unit/sql_helper_spec.rb +2 -2
  56. data/spec/unit/throttler/{slave_lag_spec.rb → replica_lag_spec.rb} +84 -92
  57. data/spec/unit/throttler/threads_running_spec.rb +18 -0
  58. data/spec/unit/throttler_spec.rb +8 -8
  59. metadata +26 -12
  60. data/.travis.yml +0 -21
  61. data/gemfiles/activerecord_5.2.gemfile +0 -9
  62. data/gemfiles/activerecord_5.2.gemfile.lock +0 -65
  63. data/gemfiles/activerecord_6.0.gemfile.lock +0 -67
@@ -1,5 +1,4 @@
1
1
  require 'minitest/autorun'
2
- require 'mysql2'
3
2
  require 'lhm'
4
3
  require 'toxiproxy'
5
4
 
@@ -50,7 +49,7 @@ describe Lhm::SqlRetry, "ProxiSQL tests for LHM retry" do
50
49
  end
51
50
  end
52
51
 
53
- assert_equal @connection.execute("Select * from #{DBConnectionHelper.test_table_name} WHERE id=2000").to_a.first.first, 2000
52
+ assert_equal 2000, @connection.select_one("SELECT * FROM #{DBConnectionHelper.test_table_name} WHERE id=2000")["id"]
54
53
 
55
54
  logs = @logger.string.split("\n")
56
55
 
@@ -23,7 +23,7 @@ describe Lhm::Table do
23
23
  end
24
24
 
25
25
  it 'should parse columns' do
26
- value(@table.columns['id'][:type]).must_match(/(bigint|int)\(\d+\)/)
26
+ value(@table.columns['id'][:type]).must_match(/(bigint|int)(\(\d+\))?/)
27
27
  end
28
28
 
29
29
  it 'should return true for method that should be renamed' do
@@ -7,7 +7,7 @@ module ToxiproxyHelper
7
7
  def included(base)
8
8
  Toxiproxy.reset
9
9
 
10
- # listen on localhost, but toxiproxy is in a container itself, thus the upstream uses the Docker-Compose DNS
10
+ # listen on localhost, but toxiproxy is in a container itself, thus the upstream uses the Podman-Compose DNS
11
11
  Toxiproxy.populate(
12
12
  [
13
13
  {
data/spec/test_helper.rb CHANGED
@@ -14,6 +14,7 @@ require 'after_do'
14
14
  require 'byebug'
15
15
  require 'pathname'
16
16
  require 'lhm'
17
+ require 'active_record'
17
18
 
18
19
  $project = Pathname.new(File.dirname(__FILE__) + '/..').cleanpath
19
20
  $spec = $project.join('spec')
@@ -21,8 +22,31 @@ $fixtures = $spec.join('fixtures')
21
22
 
22
23
  $db_name = 'test'
23
24
 
24
- require 'active_record'
25
- require 'mysql2'
25
+ Database = Struct.new(:adapter, :client, :error_class, :timeout_error) do
26
+ def query(connection, sql)
27
+ results = connection.query(sql)
28
+ results = results.each_hash if adapter == "trilogy"
29
+ results
30
+ end
31
+ end
32
+
33
+ DATABASE =
34
+ case ENV['DATABASE_ADAPTER']
35
+ when 'trilogy'
36
+ require 'trilogy'
37
+
38
+ if ActiveRecord.version < ::Gem::Version.new('7.1.0')
39
+ require 'activerecord-trilogy-adapter'
40
+ require 'trilogy_adapter/connection'
41
+
42
+ ActiveRecord::Base.public_send :extend, TrilogyAdapter::Connection
43
+ end
44
+
45
+ Database.new('trilogy', Trilogy, Trilogy::BaseError, Trilogy::TimeoutError)
46
+ else
47
+ require 'mysql2'
48
+ Database.new('mysql2', Mysql2::Client, Mysql2::Error, Mysql2::Error::TimeoutError)
49
+ end
26
50
 
27
51
  logger = Logger.new STDOUT
28
52
  logger.level = Logger::WARN
@@ -53,7 +77,7 @@ end
53
77
 
54
78
  def init_test_db
55
79
  db_config = YAML.load_file(File.expand_path(File.dirname(__FILE__)) + '/integration/database.yml')
56
- conn = Mysql2::Client.new(
80
+ conn = DATABASE.client.new(
57
81
  :host => '127.0.0.1',
58
82
  :username => db_config['master']['user'],
59
83
  :password => db_config['master']['password'],
@@ -21,8 +21,8 @@ describe Lhm::AtomicSwitcher do
21
21
  describe 'atomic switch' do
22
22
  it 'should perform a single atomic rename' do
23
23
  value(@switcher.atomic_switch).must_equal(
24
- "rename table `origin` to `#{ @migration.archive_name }`, " \
25
- '`destination` to `origin`'
24
+ "RENAME TABLE `origin` TO `#{ @migration.archive_name }`, " \
25
+ '`destination` TO `origin`'
26
26
  )
27
27
  end
28
28
  end
@@ -20,7 +20,7 @@ describe Lhm::Chunker do
20
20
  @destination = Lhm::Table.new('bar')
21
21
  @migration = Lhm::Migration.new(@origin, @destination)
22
22
  @connection = mock()
23
- @connection.stubs(:execute).returns([["dummy"]])
23
+ @connection.stubs(:select_value).returns("dummy")
24
24
  # This is a poor man's stub
25
25
  @throttler = Object.new
26
26
  def @throttler.run
@@ -42,11 +42,11 @@ describe Lhm::Chunker do
42
42
  5
43
43
  end
44
44
 
45
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 4/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(7)
46
- @connection.expects(:select_value).with(regexp_matches(/where id >= 8 order by id limit 1 offset 4/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(21)
47
- @connection.expects(:update).with(regexp_matches(/between 1 and 7/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
48
- @connection.expects(:update).with(regexp_matches(/between 8 and 10/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
49
- @connection.expects(:execute).twice.with(regexp_matches(/show warnings/),EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
45
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 4/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(7)
46
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 8 order by id limit 1 offset 4/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(21)
47
+ @connection.expects(:update).with(regexp_matches(/between 1 and 7/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
48
+ @connection.expects(:update).with(regexp_matches(/between 8 and 10/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
49
+ @connection.expects(:select_all).twice.with(regexp_matches(/show warnings/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
50
50
 
51
51
  @chunker.run
52
52
  end
@@ -57,17 +57,17 @@ describe Lhm::Chunker do
57
57
  2
58
58
  end
59
59
 
60
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
61
- @connection.expects(:select_value).with(regexp_matches(/where id >= 3 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(4)
62
- @connection.expects(:select_value).with(regexp_matches(/where id >= 5 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(6)
63
- @connection.expects(:select_value).with(regexp_matches(/where id >= 7 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(8)
64
- @connection.expects(:select_value).with(regexp_matches(/where id >= 9 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(10)
60
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
61
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 3 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(4)
62
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 5 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(6)
63
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 7 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(8)
64
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 9 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(10)
65
65
 
66
- @connection.expects(:update).with(regexp_matches(/between 1 and 2/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
67
- @connection.expects(:update).with(regexp_matches(/between 3 and 4/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
68
- @connection.expects(:update).with(regexp_matches(/between 5 and 6/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
69
- @connection.expects(:update).with(regexp_matches(/between 7 and 8/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
70
- @connection.expects(:update).with(regexp_matches(/between 9 and 10/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
66
+ @connection.expects(:update).with(regexp_matches(/between 1 and 2/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
67
+ @connection.expects(:update).with(regexp_matches(/between 3 and 4/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
68
+ @connection.expects(:update).with(regexp_matches(/between 5 and 6/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
69
+ @connection.expects(:update).with(regexp_matches(/between 7 and 8/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
70
+ @connection.expects(:update).with(regexp_matches(/between 9 and 10/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
71
71
 
72
72
  @chunker.run
73
73
  end
@@ -84,17 +84,17 @@ describe Lhm::Chunker do
84
84
  end
85
85
  end
86
86
 
87
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
88
- @connection.expects(:select_value).with(regexp_matches(/where id >= 3 order by id limit 1 offset 2/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(5)
89
- @connection.expects(:select_value).with(regexp_matches(/where id >= 6 order by id limit 1 offset 2/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(8)
90
- @connection.expects(:select_value).with(regexp_matches(/where id >= 9 order by id limit 1 offset 2/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
87
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
88
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 3 order by id limit 1 offset 2/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(5)
89
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 6 order by id limit 1 offset 2/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(8)
90
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 9 order by id limit 1 offset 2/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
91
91
 
92
- @connection.expects(:update).with(regexp_matches(/between 1 and 2/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
93
- @connection.expects(:update).with(regexp_matches(/between 3 and 5/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
94
- @connection.expects(:update).with(regexp_matches(/between 6 and 8/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
95
- @connection.expects(:update).with(regexp_matches(/between 9 and 10/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
92
+ @connection.expects(:update).with(regexp_matches(/between 1 and 2/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
93
+ @connection.expects(:update).with(regexp_matches(/between 3 and 5/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
94
+ @connection.expects(:update).with(regexp_matches(/between 6 and 8/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
95
+ @connection.expects(:update).with(regexp_matches(/between 9 and 10/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
96
96
 
97
- @connection.expects(:execute).twice.with(regexp_matches(/show warnings/),EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
97
+ @connection.expects(:select_all).twice.with(regexp_matches(/show warnings/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
98
98
 
99
99
  @chunker.run
100
100
  end
@@ -104,8 +104,8 @@ describe Lhm::Chunker do
104
104
  :start => 1,
105
105
  :limit => 1)
106
106
 
107
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 0/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
108
- @connection.expects(:update).with(regexp_matches(/between 1 and 1/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
107
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 0/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
108
+ @connection.expects(:update).with(regexp_matches(/between 1 and 1/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
109
109
 
110
110
  @chunker.run
111
111
  end
@@ -118,17 +118,17 @@ describe Lhm::Chunker do
118
118
  2
119
119
  end
120
120
 
121
- @connection.expects(:select_value).with(regexp_matches(/where id >= 2 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(3)
122
- @connection.expects(:select_value).with(regexp_matches(/where id >= 4 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(5)
123
- @connection.expects(:select_value).with(regexp_matches(/where id >= 6 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(7)
124
- @connection.expects(:select_value).with(regexp_matches(/where id >= 8 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(9)
125
- @connection.expects(:select_value).with(regexp_matches(/where id >= 10 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
121
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 2 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(3)
122
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 4 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(5)
123
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 6 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(7)
124
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 8 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(9)
125
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 10 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(nil)
126
126
 
127
- @connection.expects(:update).with(regexp_matches(/between 2 and 3/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
128
- @connection.expects(:update).with(regexp_matches(/between 4 and 5/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
129
- @connection.expects(:update).with(regexp_matches(/between 6 and 7/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
130
- @connection.expects(:update).with(regexp_matches(/between 8 and 9/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
131
- @connection.expects(:update).with(regexp_matches(/between 10 and 10/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
127
+ @connection.expects(:update).with(regexp_matches(/between 2 and 3/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
128
+ @connection.expects(:update).with(regexp_matches(/between 4 and 5/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
129
+ @connection.expects(:update).with(regexp_matches(/between 6 and 7/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
130
+ @connection.expects(:update).with(regexp_matches(/between 8 and 9/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(2)
131
+ @connection.expects(:update).with(regexp_matches(/between 10 and 10/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
132
132
 
133
133
  @chunker.run
134
134
  end
@@ -142,9 +142,9 @@ describe Lhm::Chunker do
142
142
  2
143
143
  end
144
144
 
145
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
146
- @connection.expects(:update).with(regexp_matches(/where \(foo.created_at > '2013-07-10' or foo.baz = 'quux'\) and `foo`/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
147
- @connection.expects(:execute).with(regexp_matches(/show warnings/),EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
145
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
146
+ @connection.expects(:update).with(regexp_matches(/where \(foo.created_at > '2013-07-10' or foo.baz = 'quux'\) and `foo`/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
147
+ @connection.expects(:select_all).with(regexp_matches(/show warnings/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
148
148
 
149
149
  def @migration.conditions
150
150
  "where foo.created_at > '2013-07-10' or foo.baz = 'quux'"
@@ -162,9 +162,9 @@ describe Lhm::Chunker do
162
162
  2
163
163
  end
164
164
 
165
- @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/),EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
166
- @connection.expects(:update).with(regexp_matches(/inner join bar on foo.id = bar.foo_id and/),EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
167
- @connection.expects(:execute).with(regexp_matches(/show warnings/),EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
165
+ @connection.expects(:select_value).with(regexp_matches(/where id >= 1 order by id limit 1 offset 1/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns(2)
166
+ @connection.expects(:update).with(regexp_matches(/inner join bar on foo.id = bar.foo_id and/i), EXPECTED_RETRY_FLAGS_CHUNK_INSERT).returns(1)
167
+ @connection.expects(:select_all).with(regexp_matches(/show warnings/i), EXPECTED_RETRY_FLAGS_CHUNKER).returns([])
168
168
 
169
169
  def @migration.conditions
170
170
  'inner join bar on foo.id = bar.foo_id'
@@ -93,7 +93,7 @@ describe Lhm::Connection do
93
93
  it "Queries should be tagged with ProxySQL tag if reconnect_with_consistent_host is enabled" do
94
94
  ar_connection = mock()
95
95
  ar_connection.expects(:public_send).with(:select_value, "SHOW TABLES #{Lhm::ProxySQLHelper::ANNOTATION}").returns("dummy")
96
- ar_connection.stubs(:execute).times(4).returns([["dummy"]])
96
+ ar_connection.stubs(:select_value).times(4).returns("dummy")
97
97
  ar_connection.stubs(:active?).returns(true)
98
98
 
99
99
  connection = Lhm::Connection.new(connection: ar_connection, options: {
@@ -108,4 +108,4 @@ describe Lhm::Connection do
108
108
 
109
109
  assert_equal val, "dummy"
110
110
  end
111
- end
111
+ end
@@ -63,10 +63,9 @@ describe Lhm::Entangler do
63
63
  it 'should retry trigger creation when it hits a lock wait timeout' do
64
64
  tries = 1
65
65
  ar_connection = mock()
66
+ ar_connection.stubs(:select_value).returns("dummy")
66
67
  ar_connection.stubs(:execute)
67
- .returns([["dummy"]], [["dummy"]], [["dummy"]])
68
- .then
69
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction')
68
+ .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction')
70
69
  ar_connection.stubs(:active?).returns(true)
71
70
 
72
71
  connection = Lhm::Connection.new(connection: ar_connection, options: {
@@ -79,15 +78,14 @@ describe Lhm::Entangler do
79
78
 
80
79
  @entangler = Lhm::Entangler.new(@migration, connection)
81
80
 
82
- assert_raises(Mysql2::Error) { @entangler.before }
81
+ assert_raises(ActiveRecord::StatementInvalid) { @entangler.before }
83
82
  end
84
83
 
85
84
  it 'should not retry trigger creation with other mysql errors' do
86
85
  ar_connection = mock()
86
+ ar_connection.stubs(:select_value).returns("dummy")
87
87
  ar_connection.stubs(:execute)
88
- .returns([["dummy"]], [["dummy"]], [["dummy"]])
89
- .then
90
- .raises(Mysql2::Error, 'The MySQL server is running with the --read-only option so it cannot execute this statement.')
88
+ .raises(DATABASE.error_class, 'The MySQL server is running with the --read-only option so it cannot execute this statement.')
91
89
  ar_connection.stubs(:active?).returns(true)
92
90
  connection = Lhm::Connection.new(connection: ar_connection, options: {
93
91
  reconnect_with_consistent_host: true,
@@ -97,15 +95,14 @@ describe Lhm::Entangler do
97
95
  })
98
96
 
99
97
  @entangler = Lhm::Entangler.new(@migration, connection)
100
- assert_raises(Mysql2::Error) { @entangler.before }
98
+ assert_raises(DATABASE.error_class) { @entangler.before }
101
99
  end
102
100
 
103
101
  it 'should succesfully finish after retrying' do
104
102
  ar_connection = mock()
103
+ ar_connection.stubs(:select_value).returns("dummy")
105
104
  ar_connection.stubs(:execute)
106
- .returns([["dummy"]], [["dummy"]], [["dummy"]])
107
- .then
108
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction')
105
+ .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction')
109
106
  .then
110
107
  .returns([["dummy"]])
111
108
  ar_connection.stubs(:active?).returns(true)
@@ -124,22 +121,15 @@ describe Lhm::Entangler do
124
121
 
125
122
  it 'should retry as many times as specified by configuration' do
126
123
  ar_connection = mock()
124
+ ar_connection.stubs(:select_value).returns("dummy")
127
125
  ar_connection.stubs(:execute)
128
- .returns([["dummy"]], [["dummy"]], [["dummy"]]) # initial
129
- .then
130
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction')
131
- .then
132
- .returns([["dummy"]]) # reconnect 1
133
- .then
134
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction')
135
- .then
136
- .returns([["dummy"]]) # reconnect 2
126
+ .raises(DATABASE.error_class, 'Lock wait timeout exceeded; try restarting transaction')
137
127
  .then
138
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction')
128
+ .raises(DATABASE.error_class, 'Lock wait timeout exceeded; try restarting transaction')
139
129
  .then
140
- .returns([["dummy"]]) # reconnect 3
130
+ .raises(DATABASE.error_class, 'Lock wait timeout exceeded; try restarting transaction')
141
131
  .then
142
- .raises(Mysql2::Error, 'Lock wait timeout exceeded; try restarting transaction') # final error
132
+ .raises(DATABASE.error_class, 'Lock wait timeout exceeded; try restarting transaction') # final error
143
133
  ar_connection.stubs(:active?).returns(true)
144
134
 
145
135
  connection = Lhm::Connection.new(connection: ar_connection, options: {
@@ -152,7 +142,7 @@ describe Lhm::Entangler do
152
142
 
153
143
  @entangler = Lhm::Entangler.new(@migration, connection)
154
144
 
155
- assert_raises(Mysql2::Error) { @entangler.before }
145
+ assert_raises(DATABASE.error_class) { @entangler.before }
156
146
  end
157
147
 
158
148
  describe 'super long table names' do
@@ -70,15 +70,11 @@ describe Lhm::Printer do
70
70
  end
71
71
 
72
72
  it 'prints the dots' do
73
- mock = MiniTest::Mock.new
74
- 10.times do
75
- mock.expect(:write, :return_value, ['.'])
76
- end
73
+ mock = mock("output")
74
+ mock.expects(:write).with('.').times(10)
77
75
 
78
76
  @printer.instance_variable_set(:@output, mock)
79
77
  10.times { @printer.notify }
80
-
81
- mock.verify
82
78
  end
83
79
 
84
80
  end
@@ -22,7 +22,7 @@ describe Lhm::SqlHelper do
22
22
  end
23
23
 
24
24
  it 'should quote column names in index specification' do
25
- value(Lhm::SqlHelper.idx_spec(['title(10)', 'album']))
26
- .must_equal('`title`(10), `album`')
25
+ value(Lhm::SqlHelper.idx_spec(['title(10)', 'name (6)', 'album']))
26
+ .must_equal('`title`(10), `name`(6), `album`')
27
27
  end
28
28
  end