lhm-shopify 4.0.0 → 4.1.1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +20 -18
  3. data/Appraisals +5 -11
  4. data/CHANGELOG.md +9 -0
  5. data/Gemfile.lock +22 -7
  6. data/README.md +7 -7
  7. data/dev.yml +4 -1
  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 +3 -3
  11. data/gemfiles/activerecord_6.1.gemfile +1 -0
  12. data/gemfiles/activerecord_6.1.gemfile.lock +8 -2
  13. data/gemfiles/activerecord_7.0.gemfile +1 -0
  14. data/gemfiles/activerecord_7.0.gemfile.lock +7 -1
  15. data/gemfiles/{activerecord_6.0.gemfile → activerecord_7.1.gemfile} +1 -1
  16. data/gemfiles/{activerecord_7.1.0.beta1.gemfile.lock → activerecord_7.1.gemfile.lock} +10 -8
  17. data/lhm.gemspec +1 -0
  18. data/lib/lhm/atomic_switcher.rb +3 -3
  19. data/lib/lhm/chunker.rb +8 -7
  20. data/lib/lhm/connection.rb +9 -1
  21. data/lib/lhm/sql_retry.rb +36 -18
  22. data/lib/lhm/table.rb +3 -4
  23. data/lib/lhm/throttler/replica_lag.rb +17 -13
  24. data/lib/lhm/version.rb +1 -1
  25. data/scripts/helpers/wait-for-dbs.sh +3 -3
  26. data/scripts/mysql/writer/create_users.sql +1 -1
  27. data/spec/integration/atomic_switcher_spec.rb +4 -8
  28. data/spec/integration/chunker_spec.rb +23 -9
  29. data/spec/integration/database.yml +3 -3
  30. data/spec/integration/integration_helper.rb +11 -3
  31. data/spec/integration/lhm_spec.rb +29 -13
  32. data/spec/integration/proxysql_spec.rb +10 -10
  33. data/spec/integration/sql_retry/db_connection_helper.rb +2 -4
  34. data/spec/integration/sql_retry/lock_wait_spec.rb +7 -8
  35. data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +18 -10
  36. data/spec/integration/sql_retry/proxysql_helper.rb +1 -1
  37. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +1 -2
  38. data/spec/integration/table_spec.rb +1 -1
  39. data/spec/test_helper.rb +27 -3
  40. data/spec/unit/atomic_switcher_spec.rb +2 -2
  41. data/spec/unit/chunker_spec.rb +43 -43
  42. data/spec/unit/connection_spec.rb +2 -2
  43. data/spec/unit/entangler_spec.rb +14 -24
  44. data/spec/unit/throttler/replica_lag_spec.rb +6 -14
  45. metadata +21 -8
  46. data/.travis.yml +0 -21
  47. data/gemfiles/activerecord_6.0.gemfile.lock +0 -71
  48. data/gemfiles/activerecord_7.1.0.beta1.gemfile +0 -7
data/lib/lhm/sql_retry.rb CHANGED
@@ -105,9 +105,7 @@ module Lhm
105
105
  def mysql_single_value(name)
106
106
  query = Lhm::ProxySQLHelper.tagged("SELECT #{name} LIMIT 1")
107
107
 
108
- @connection.execute(query).to_a.first.tap do |record|
109
- return record&.first
110
- end
108
+ @connection.select_value(query)
111
109
  end
112
110
 
113
111
  def same_host_as_initial?
@@ -140,32 +138,22 @@ module Lhm
140
138
  log_with_prefix("Reconnected to wrong host. Started migration on: #{@initial_hostname} (server_id: #{@initial_server_id}), but reconnected to: #{hostname} (server_id: #{server_id}).", :error)
141
139
  return false
142
140
  end
143
- rescue StandardError => e
141
+ rescue ActiveRecord::ConnectionNotEstablished
144
142
  # Retry if ActiveRecord cannot reach host
145
- next if /Lost connection to MySQL server at 'reading initial communication packet'/ === e.message
143
+ next
144
+ rescue StandardError => e
146
145
  log_with_prefix("Encountered error: [#{e.class}] #{e.message}. Will stop reconnection procedure.", :info)
147
146
  return false
148
147
  end
149
148
  end
149
+
150
150
  false
151
151
  end
152
152
 
153
153
  # For a full list of configuration options see https://github.com/kamui/retriable
154
154
  def default_retry_config
155
155
  {
156
- on: {
157
- StandardError => [
158
- /Lock wait timeout exceeded/,
159
- /Timeout waiting for a response from the last query/,
160
- /Deadlock found when trying to get lock/,
161
- /Query execution was interrupted/,
162
- /Lost connection to MySQL server during query/,
163
- /Max connect timeout reached/,
164
- /Unknown MySQL server host/,
165
- /connection is locked to hostgroup/,
166
- /The MySQL server is running with the --read-only option so it cannot execute this statement/,
167
- ]
168
- },
156
+ on: retriable_mysql2_errors || retriable_trilogy_errors,
169
157
  multiplier: 1, # each successive interval grows by this factor
170
158
  base_interval: 1, # the initial interval in seconds between tries.
171
159
  tries: 20, # Number of attempts to make at running your code block (includes initial attempt).
@@ -176,5 +164,35 @@ module Lhm
176
164
  end
177
165
  }.freeze
178
166
  end
167
+
168
+ def retriable_mysql2_errors
169
+ return unless defined?(Mysql2::Error)
170
+
171
+ {
172
+ StandardError => [
173
+ /Lock wait timeout exceeded/,
174
+ /Timeout waiting for a response from the last query/,
175
+ /Deadlock found when trying to get lock/,
176
+ /Query execution was interrupted/,
177
+ /Lost connection to MySQL server during query/,
178
+ /Max connect timeout reached/,
179
+ /Unknown MySQL server host/,
180
+ /connection is locked to hostgroup/,
181
+ /The MySQL server is running with the --read-only option so it cannot execute this statement/,
182
+ ],
183
+ }
184
+ end
185
+
186
+ def retriable_trilogy_errors
187
+ return unless defined?(Trilogy::BaseError)
188
+
189
+ {
190
+ ActiveRecord::StatementInvalid => [
191
+ # Those sometimes appear as Trilogy::TimeoutError, and sometimes as ActiveRecord::StatementInvalid
192
+ /Lock wait timeout exceeded/,
193
+ ],
194
+ Trilogy::ConnectionError => nil,
195
+ }
196
+ end
179
197
  end
180
198
  end
data/lib/lhm/table.rb CHANGED
@@ -39,10 +39,9 @@ module Lhm
39
39
  end
40
40
 
41
41
  def ddl
42
- sql = "show create table `#{ @table_name }`"
43
- specification = nil
44
- @connection.execute(sql).each { |row| specification = row.last }
45
- specification
42
+ query = "SHOW CREATE TABLE #{ @connection.quote_table_name(@table_name) }"
43
+
44
+ @connection.select_one(query)["Create Table"]
46
45
  end
47
46
 
48
47
  def parse
@@ -91,6 +91,14 @@ module Lhm
91
91
 
92
92
  attr_reader :host, :connection
93
93
 
94
+ def self.client
95
+ defined?(Mysql2::Client) ? Mysql2::Client : Trilogy
96
+ end
97
+
98
+ def self.client_error
99
+ defined?(Mysql2::Error) ? Mysql2::Error : Trilogy::Error
100
+ end
101
+
94
102
  def initialize(host, connection_config = nil)
95
103
  @host = host
96
104
  @connection_config = prepare_connection_config(connection_config)
@@ -108,13 +116,11 @@ module Lhm
108
116
  private
109
117
 
110
118
  def client(config)
111
- begin
112
- Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
113
- Mysql2::Client.new(config)
114
- rescue Mysql2::Error => e
115
- Lhm.logger.info "Error connecting to #{@host}: #{e}"
116
- nil
117
- end
119
+ Lhm.logger.info "Connecting to #{@host} on database: #{config[:database]}"
120
+ self.class.client.new(config)
121
+ rescue self.class.client_error => e
122
+ Lhm.logger.info "Error connecting to #{@host}: #{e}"
123
+ nil
118
124
  end
119
125
 
120
126
  def prepare_connection_config(config_proc)
@@ -133,12 +139,10 @@ module Lhm
133
139
  end
134
140
 
135
141
  def query_connection(query, result)
136
- begin
137
- @connection.query(query).map { |row| row[result] }
138
- rescue Mysql2::Error => e
139
- Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
140
- [nil]
141
- end
142
+ @connection.query(query).map { |row| row[result] }
143
+ rescue self.class.client_error => e
144
+ Lhm.logger.info "Unable to connect and/or query #{host}: #{e}"
145
+ [nil]
142
146
  end
143
147
 
144
148
  private
data/lib/lhm/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Schmidt
3
3
 
4
4
  module Lhm
5
- VERSION = '4.0.0'
5
+ VERSION = '4.1.1'
6
6
  end
@@ -1,19 +1,19 @@
1
1
  #!/bin/bash
2
2
  # Wait for writer
3
3
  echo "Waiting for MySQL-1: "
4
- while ! (mysqladmin ping --host="127.0.0.1" --port=33006 --user=root --password=password --silent 2> /dev/null); do
4
+ while ! (mysqladmin ping --host="127.0.0.1" --port=13006 --user=root --password=password --silent 2> /dev/null); do
5
5
  echo -ne "."
6
6
  sleep 1
7
7
  done
8
8
  # Wait for reader
9
9
  echo "Waiting for MySQL-2: "
10
- while ! (mysqladmin ping --host="127.0.0.1" --port=33007 --user=root --password=password --silent 2> /dev/null); do
10
+ while ! (mysqladmin ping --host="127.0.0.1" --port=13007 --user=root --password=password --silent 2> /dev/null); do
11
11
  echo -ne "."
12
12
  sleep 1
13
13
  done
14
14
  # Wait for proxysql
15
15
  echo "Waiting for ProxySQL:"
16
- while ! (mysqladmin ping --host="127.0.0.1" --port=33005 --user=root --password=password --silent 2> /dev/null); do
16
+ while ! (mysqladmin ping --host="127.0.0.1" --port=13005 --user=root --password=password --silent 2> /dev/null); do
17
17
  echo -ne "."
18
18
  sleep 1
19
19
  done
@@ -3,4 +3,4 @@ CREATE USER IF NOT EXISTS 'writer'@'%' IDENTIFIED BY 'password';
3
3
  CREATE USER IF NOT EXISTS 'reader'@'%' IDENTIFIED BY 'password';
4
4
 
5
5
  CREATE USER IF NOT EXISTS 'replication'@'%' IDENTIFIED BY 'password';
6
- GRANT REPLICATION SLAVE ON *.* TO' replication'@'%' IDENTIFIED BY 'password';
6
+ GRANT REPLICATION SLAVE ON *.* TO' replication'@'%';
@@ -33,8 +33,8 @@ describe Lhm::AtomicSwitcher do
33
33
  ar_connection = mock()
34
34
  ar_connection.stubs(:data_source_exists?).returns(true)
35
35
  ar_connection.stubs(:active?).returns(true)
36
- ar_connection.stubs(:execute).returns([["dummy"]], [["dummy"]], [["dummy"]])
37
- .then
36
+ ar_connection.stubs(:select_value).returns("dummy")
37
+ ar_connection.stubs(:execute)
38
38
  .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
39
39
  .then
40
40
  .returns([["dummy"]]) # Matches initial host -> triggers retry
@@ -62,16 +62,12 @@ describe Lhm::AtomicSwitcher do
62
62
  ar_connection = mock()
63
63
  ar_connection.stubs(:data_source_exists?).returns(true)
64
64
  ar_connection.stubs(:active?).returns(true)
65
- ar_connection.stubs(:execute).returns([["dummy"]], [["dummy"]], [["dummy"]])
66
- .then
65
+ ar_connection.stubs(:select_value).returns("dummy")
66
+ ar_connection.stubs(:execute)
67
67
  .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
68
68
  .then
69
- .returns([["dummy"]]) # triggers retry 1
70
- .then
71
69
  .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.')
72
70
  .then
73
- .returns([["dummy"]]) # triggers retry 2
74
- .then
75
71
  .raises(ActiveRecord::StatementInvalid, 'Lock wait timeout exceeded; try restarting transaction.') # triggers retry 2
76
72
 
77
73
  connection = Lhm::Connection.new(connection: ar_connection, options: {
@@ -31,7 +31,6 @@ describe Lhm::Chunker do
31
31
  replica do
32
32
  value(count_all(@destination.name)).must_equal(1)
33
33
  end
34
-
35
34
  end
36
35
 
37
36
  it 'should copy and ignore duplicate primary key' do
@@ -39,7 +38,7 @@ describe Lhm::Chunker do
39
38
  execute("insert into origin set id = 1002 ")
40
39
  execute("insert into destination set id = 1002 ")
41
40
 
42
- Lhm::Chunker.new(@migration, connection, {throttler: throttler, printer: printer} ).run
41
+ Lhm::Chunker.new(@migration, connection, {raise_on_warnings: true, throttler: throttler, printer: printer} ).run
43
42
 
44
43
  replica do
45
44
  value(count_all(@destination.name)).must_equal(2)
@@ -55,7 +54,7 @@ describe Lhm::Chunker do
55
54
  execute("insert into composite_primary_key set id = 1002, shop_id = 1")
56
55
  execute("insert into composite_primary_key_dest set id = 1002, shop_id = 1")
57
56
 
58
- Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
57
+ Lhm::Chunker.new(migration, connection, {raise_on_warning: true, throttler: throttler, printer: printer} ).run
59
58
 
60
59
  replica do
61
60
  value(count_all(destination.name)).must_equal(2)
@@ -74,7 +73,8 @@ describe Lhm::Chunker do
74
73
  Lhm::Chunker.new(migration, connection, {raise_on_warnings: true, throttler: throttler, printer: printer} ).run
75
74
  end
76
75
 
77
- assert_match "Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'", exception.message
76
+ error_key = index_key("custom_primary_key_dest", "index_custom_primary_key_on_id")
77
+ assert_match "Unexpected warning found for inserted row: Duplicate entry '1001' for key '#{error_key}'", exception.message
78
78
  end
79
79
 
80
80
  it 'should copy and warn on unexpected warnings by default' do
@@ -87,8 +87,10 @@ describe Lhm::Chunker do
87
87
 
88
88
  Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
89
89
 
90
+ error_key = index_key("custom_primary_key_dest", "index_custom_primary_key_on_id")
91
+
90
92
  assert_equal 2, log_messages.length
91
- assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
93
+ assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key '#{error_key}'"), log_messages
92
94
  end
93
95
 
94
96
  it 'should log two times for two unexpected warnings' do
@@ -103,9 +105,11 @@ describe Lhm::Chunker do
103
105
 
104
106
  Lhm::Chunker.new(migration, connection, {throttler: throttler, printer: printer} ).run
105
107
 
108
+ error_key = index_key("custom_primary_key_dest", "index_custom_primary_key_on_id")
109
+
106
110
  assert_equal 3, log_messages.length
107
- assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
108
- assert log_messages[2].include?("Unexpected warning found for inserted row: Duplicate entry '1002' for key 'index_custom_primary_key_on_id'"), log_messages
111
+ assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key '#{error_key}'"), log_messages
112
+ assert log_messages[2].include?("Unexpected warning found for inserted row: Duplicate entry '1002' for key '#{error_key}'"), log_messages
109
113
  end
110
114
 
111
115
  it 'should copy and warn on unexpected warnings' do
@@ -118,8 +122,10 @@ describe Lhm::Chunker do
118
122
 
119
123
  Lhm::Chunker.new(migration, connection, {raise_on_warnings: false, throttler: throttler, printer: printer} ).run
120
124
 
125
+ error_key = index_key("custom_primary_key_dest", "index_custom_primary_key_on_id")
126
+
121
127
  assert_equal 2, log_messages.length
122
- assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key 'index_custom_primary_key_on_id'"), log_messages
128
+ assert log_messages[1].include?("Unexpected warning found for inserted row: Duplicate entry '1001' for key '#{error_key}'"), log_messages
123
129
  end
124
130
 
125
131
  it 'should create the modified destination, even if the source is empty' do
@@ -222,7 +228,7 @@ describe Lhm::Chunker do
222
228
  def throttler.replica_connection(replica)
223
229
  config = ActiveRecord::Base.connection_pool.db_config.configuration_hash.dup
224
230
  config[:host] = replica
225
- config[:port] = 33007
231
+ config[:port] = 13007
226
232
  ActiveRecord::Base.send('mysql2_connection', config)
227
233
  end
228
234
  end
@@ -261,4 +267,12 @@ describe Lhm::Chunker do
261
267
  end
262
268
  end
263
269
  end
270
+
271
+ def index_key(table_name, index_name)
272
+ if mysql_version.start_with?("8")
273
+ "#{table_name}.#{index_name}"
274
+ else
275
+ index_name
276
+ end
277
+ end
264
278
  end
@@ -2,17 +2,17 @@ master:
2
2
  host: mysql-1
3
3
  user: root
4
4
  password: password
5
- port: 33006
5
+ port: 13006
6
6
  replica:
7
7
  host: mysql-2
8
8
  user: root
9
9
  password: password
10
- port: 33007
10
+ port: 13007
11
11
  proxysql:
12
12
  host: proxysql
13
13
  user: root
14
14
  password: password
15
- port: 33005
15
+ port: 13005
16
16
  master_toxic:
17
17
  host: toxiproxy
18
18
  user: root
@@ -22,7 +22,7 @@ module IntegrationHelper
22
22
  def self.included(base)
23
23
  base.after(:each) do
24
24
  cleanup_connection = new_mysql_connection
25
- results = cleanup_connection.query("SELECT table_name FROM information_schema.tables WHERE table_schema = '#{$db_name}';")
25
+ results = DATABASE.query(cleanup_connection, "SELECT table_name FROM information_schema.tables WHERE table_schema = '#{$db_name}';")
26
26
  table_names_for_cleanup = results.map { |row| "#{$db_name}." + row.values.first }
27
27
  cleanup_connection.query("DROP TABLE IF EXISTS #{table_names_for_cleanup.join(', ')};") if table_names_for_cleanup.length > 0
28
28
  end
@@ -35,6 +35,14 @@ module IntegrationHelper
35
35
  @connection
36
36
  end
37
37
 
38
+ def mysql_version
39
+ @mysql_version ||= begin
40
+ # This SQL returns a value of shape: X.Y.ZZ-AA-log
41
+ result = connection.query("SELECT VERSION()")
42
+ result.dig(0, 0).split("-", 2)[0]
43
+ end
44
+ end
45
+
38
46
  def connect_proxysql!
39
47
  connect!(
40
48
  '127.0.0.1',
@@ -81,7 +89,7 @@ module IntegrationHelper
81
89
 
82
90
  def ar_conn(host, port, user, password)
83
91
  ActiveRecord::Base.establish_connection(
84
- :adapter => 'mysql2',
92
+ :adapter => DATABASE.adapter,
85
93
  :host => host,
86
94
  :username => user,
87
95
  :port => port,
@@ -171,7 +179,7 @@ module IntegrationHelper
171
179
  end
172
180
 
173
181
  def new_mysql_connection(role='master')
174
- Mysql2::Client.new(
182
+ DATABASE.client.new(
175
183
  host: '127.0.0.1',
176
184
  database: $db_name,
177
185
  username: $db_config[role]['user'],
@@ -9,6 +9,10 @@ describe Lhm do
9
9
 
10
10
  before(:each) { connect_master!; Lhm.cleanup(true) }
11
11
 
12
+ let(:collation) do
13
+ mysql_version.start_with?("8.0") ? "utf8mb3_general_ci" : "utf8_general_ci"
14
+ end
15
+
12
16
  describe 'id column requirement' do
13
17
  it 'should migrate the table when id is pk' do
14
18
  table_create(:users)
@@ -17,9 +21,11 @@ describe Lhm do
17
21
  t.add_column(:logins, "int(12) default '0'")
18
22
  end
19
23
 
24
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
25
+
20
26
  replica do
21
27
  value(table_read(:users).columns['logins']).must_equal({
22
- :type => 'int(12)',
28
+ :type => expected_type,
23
29
  :is_nullable => 'YES',
24
30
  :column_default => '0',
25
31
  :comment => '',
@@ -35,9 +41,11 @@ describe Lhm do
35
41
  t.add_column(:logins, "int(12) default '0'")
36
42
  end
37
43
 
44
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
45
+
38
46
  replica do
39
47
  value(table_read(:custom_primary_key).columns['logins']).must_equal({
40
- :type => 'int(12)',
48
+ :type => expected_type,
41
49
  :is_nullable => 'YES',
42
50
  :column_default => '0',
43
51
  :comment => '',
@@ -53,9 +61,11 @@ describe Lhm do
53
61
  t.add_column(:logins, "int(12) default '0'")
54
62
  end
55
63
 
64
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
65
+
56
66
  replica do
57
67
  value(table_read(:composite_primary_key).columns['logins']).must_equal({
58
- :type => 'int(12)',
68
+ :type => expected_type,
59
69
  :is_nullable => 'YES',
60
70
  :column_default => '0',
61
71
  :comment => '',
@@ -132,9 +142,11 @@ describe Lhm do
132
142
  t.add_column(:logins, "INT(12) DEFAULT '0'")
133
143
  end
134
144
 
145
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(12)"
146
+
135
147
  replica do
136
148
  value(table_read(:users).columns['logins']).must_equal({
137
- :type => 'int(12)',
149
+ :type => expected_type,
138
150
  :is_nullable => 'YES',
139
151
  :column_default => '0',
140
152
  :comment => '',
@@ -272,7 +284,7 @@ describe Lhm do
272
284
  :is_nullable => 'NO',
273
285
  :column_default => 'none',
274
286
  :comment => '',
275
- :collate => 'utf8_general_ci',
287
+ :collate => collation,
276
288
  })
277
289
  end
278
290
  end
@@ -284,9 +296,11 @@ describe Lhm do
284
296
  t.change_column(:id, 'int(5)')
285
297
  end
286
298
 
299
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(5)"
300
+
287
301
  replica do
288
302
  value(table_read(:small_table).columns['id']).must_equal({
289
- :type => 'int(5)',
303
+ :type => expected_type,
290
304
  :is_nullable => 'NO',
291
305
  :column_default => nil,
292
306
  :comment => '',
@@ -311,7 +325,7 @@ describe Lhm do
311
325
  :is_nullable => 'YES',
312
326
  :column_default => nil,
313
327
  :comment => '',
314
- :collate => 'utf8_general_ci',
328
+ :collate => collation,
315
329
  })
316
330
 
317
331
  result = select_one('SELECT login from users')
@@ -336,7 +350,7 @@ describe Lhm do
336
350
  :is_nullable => 'YES',
337
351
  :column_default => 'Superfriends',
338
352
  :comment => '',
339
- :collate => 'utf8_general_ci',
353
+ :collate => collation,
340
354
  })
341
355
 
342
356
  result = select_one('SELECT `fnord` from users')
@@ -383,11 +397,13 @@ describe Lhm do
383
397
  t.rename_column(:reference, :ref)
384
398
  end
385
399
 
400
+ expected_type = mysql_version.start_with?("8.0") ? "int" : "int(11)"
401
+
386
402
  replica do
387
403
  table_data = table_read(:users)
388
404
  assert_nil table_data.columns['reference']
389
405
  value(table_read(:users).columns['ref']).must_equal({
390
- :type => 'int(11)',
406
+ :type => expected_type,
391
407
  :is_nullable => 'YES',
392
408
  :column_default => nil,
393
409
  :comment => 'RefComment',
@@ -418,7 +434,7 @@ describe Lhm do
418
434
  :is_nullable => 'YES',
419
435
  :column_default => nil,
420
436
  :comment => '',
421
- :collate => 'utf8_general_ci',
437
+ :collate => collation,
422
438
  })
423
439
 
424
440
  result = select_one('SELECT `fnord` from users')
@@ -443,7 +459,7 @@ describe Lhm do
443
459
  :is_nullable => 'YES',
444
460
  :column_default => nil,
445
461
  :comment => '',
446
- :collate => 'utf8_general_ci',
462
+ :collate => collation,
447
463
  })
448
464
 
449
465
  result = select_one('SELECT `user_name` from users')
@@ -470,7 +486,7 @@ describe Lhm do
470
486
  :is_nullable => 'NO',
471
487
  :column_default => nil,
472
488
  :comment => '',
473
- :collate => 'utf8_general_ci',
489
+ :collate => collation,
474
490
  })
475
491
 
476
492
  result = select_one('SELECT `user_name` from users')
@@ -517,7 +533,7 @@ describe Lhm do
517
533
  :is_nullable => 'YES',
518
534
  :column_default => 'Superfriends',
519
535
  :comment => '',
520
- :collate => 'utf8_general_ci',
536
+ :collate => collation,
521
537
  })
522
538
  end
523
539
  end
@@ -1,34 +1,34 @@
1
1
  describe "ProxySQL integration" do
2
2
  it "Should contact the writer" do
3
- conn = Mysql2::Client.new(
3
+ conn = DATABASE.client.new(
4
4
  host: '127.0.0.1',
5
5
  username: "writer",
6
6
  password: "password",
7
- port: "33005",
7
+ port: "13005",
8
8
  )
9
9
 
10
- assert_equal conn.query("SELECT @@global.hostname as host").each.first["host"], "mysql-1"
10
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host").each.first["host"], "mysql-1"
11
11
  end
12
12
 
13
13
  it "Should contact the reader" do
14
- conn = Mysql2::Client.new(
14
+ conn = DATABASE.client.new(
15
15
  host: '127.0.0.1',
16
16
  username: "reader",
17
17
  password: "password",
18
- port: "33005",
18
+ port: "13005",
19
19
  )
20
20
 
21
- assert_equal conn.query("SELECT @@global.hostname as host").each.first["host"], "mysql-2"
21
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host").each.first["host"], "mysql-2"
22
22
  end
23
23
 
24
24
  it "Should override default hostgroup from user if rule matches" do
25
- conn = Mysql2::Client.new(
25
+ conn = DATABASE.client.new(
26
26
  host: '127.0.0.1',
27
27
  username: "reader",
28
28
  password: "password",
29
- port: "33005",
29
+ port: "13005",
30
30
  )
31
31
 
32
- assert_equal conn.query("SELECT @@global.hostname as host #{Lhm::ProxySQLHelper::ANNOTATION}").each.first["host"], "mysql-1"
32
+ assert_equal DATABASE.query(conn, "SELECT @@global.hostname as host #{Lhm::ProxySQLHelper::ANNOTATION}").each.first["host"], "mysql-1"
33
33
  end
34
- end
34
+ end
@@ -1,5 +1,4 @@
1
1
  require 'yaml'
2
- require 'mysql2'
3
2
 
4
3
  class DBConnectionHelper
5
4
 
@@ -11,12 +10,11 @@ class DBConnectionHelper
11
10
  end
12
11
 
13
12
  def new_mysql_connection(role = :master, with_data = false, toxic = false)
14
-
15
13
  key = role.to_s + toxic_postfix(toxic)
16
14
 
17
15
  conn = ActiveRecord::Base.establish_connection(
18
16
  :host => '127.0.0.1',
19
- :adapter => "mysql2",
17
+ :adapter => DATABASE.adapter,
20
18
  :username => db_config[key]['user'],
21
19
  :password => db_config[key]['password'],
22
20
  :database => test_db_name,
@@ -49,4 +47,4 @@ class DBConnectionHelper
49
47
  end
50
48
  end
51
49
  end
52
- end
50
+ end
@@ -1,5 +1,4 @@
1
1
  require 'minitest/autorun'
2
- require 'mysql2'
3
2
  require 'integration/sql_retry/lock_wait_timeout_test_helper'
4
3
  require 'lhm'
5
4
 
@@ -22,7 +21,7 @@ describe Lhm::SqlRetry do
22
21
  # Assert our pre-conditions
23
22
  assert_equal 2, @helper.record_count
24
23
 
25
- Mysql2::Client.any_instance.stubs(:active?).returns(true)
24
+ DATABASE.client.any_instance.stubs(:active?).returns(true)
26
25
  end
27
26
 
28
27
  after(:each) do
@@ -43,8 +42,8 @@ describe Lhm::SqlRetry do
43
42
 
44
43
  exception = assert_raises { @helper.trigger_wait_lock }
45
44
 
46
- assert_match /Lock wait timeout exceeded; try restarting transaction/, exception.message
47
- assert_equal Mysql2::Error::TimeoutError, exception.class
45
+ assert_match Regexp.new("Lock wait timeout exceeded; try restarting transaction"), exception.message
46
+ assert_equal DATABASE.timeout_error, exception.class
48
47
 
49
48
  assert_equal 2, @helper.record_count # no records inserted
50
49
  puts "*" * 64
@@ -82,10 +81,10 @@ describe Lhm::SqlRetry do
82
81
  logs = @logger.string.split("\n")
83
82
  assert_equal 2, logs.length
84
83
 
85
- assert logs.first.include?("Mysql2::Error::TimeoutError: 'Lock wait timeout exceeded; try restarting transaction' - 1 tries")
84
+ assert logs.first.include?("Lock wait timeout exceeded; try restarting transaction' - 1 tries")
86
85
  assert logs.first.include?("0.2 seconds until the next try")
87
86
 
88
- assert logs.last.include?("Mysql2::Error::TimeoutError: 'Lock wait timeout exceeded; try restarting transaction' - 2 tries")
87
+ assert logs.last.include?("Lock wait timeout exceeded; try restarting transaction' - 2 tries")
89
88
  assert logs.last.include?("0.2 seconds until the next try")
90
89
  end
91
90
 
@@ -118,8 +117,8 @@ describe Lhm::SqlRetry do
118
117
 
119
118
  exception = assert_raises { @helper.trigger_wait_lock }
120
119
 
121
- assert_match /Lock wait timeout exceeded; try restarting transaction/, exception.message
122
- assert_equal Mysql2::Error::TimeoutError, exception.class
120
+ assert_match Regexp.new("Lock wait timeout exceeded; try restarting transaction"), exception.message
121
+ assert_equal DATABASE.timeout_error, exception.class
123
122
 
124
123
  assert_equal 2, @helper.record_count # no records inserted
125
124
  puts "*" * 64