lhm-teak 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +43 -0
  3. data/.gitignore +12 -0
  4. data/.rubocop.yml +183 -0
  5. data/.travis.yml +21 -0
  6. data/Appraisals +24 -0
  7. data/CHANGELOG.md +254 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +67 -0
  10. data/LICENSE +27 -0
  11. data/README.md +335 -0
  12. data/Rakefile +33 -0
  13. data/dev.yml +45 -0
  14. data/docker-compose.yml +60 -0
  15. data/gemfiles/activerecord_5.2.gemfile +9 -0
  16. data/gemfiles/activerecord_5.2.gemfile.lock +66 -0
  17. data/gemfiles/activerecord_6.0.gemfile +7 -0
  18. data/gemfiles/activerecord_6.0.gemfile.lock +68 -0
  19. data/gemfiles/activerecord_6.1.gemfile +7 -0
  20. data/gemfiles/activerecord_6.1.gemfile.lock +67 -0
  21. data/gemfiles/activerecord_7.0.0.alpha2.gemfile +7 -0
  22. data/gemfiles/activerecord_7.0.0.alpha2.gemfile.lock +65 -0
  23. data/lhm.gemspec +38 -0
  24. data/lib/lhm/atomic_switcher.rb +46 -0
  25. data/lib/lhm/chunk_finder.rb +62 -0
  26. data/lib/lhm/chunk_insert.rb +61 -0
  27. data/lib/lhm/chunker.rb +95 -0
  28. data/lib/lhm/cleanup/current.rb +71 -0
  29. data/lib/lhm/command.rb +48 -0
  30. data/lib/lhm/connection.rb +108 -0
  31. data/lib/lhm/entangler.rb +112 -0
  32. data/lib/lhm/intersection.rb +51 -0
  33. data/lib/lhm/invoker.rb +100 -0
  34. data/lib/lhm/locked_switcher.rb +76 -0
  35. data/lib/lhm/migration.rb +51 -0
  36. data/lib/lhm/migrator.rb +244 -0
  37. data/lib/lhm/printer.rb +63 -0
  38. data/lib/lhm/proxysql_helper.rb +10 -0
  39. data/lib/lhm/railtie.rb +9 -0
  40. data/lib/lhm/sql_helper.rb +77 -0
  41. data/lib/lhm/sql_retry.rb +180 -0
  42. data/lib/lhm/table.rb +121 -0
  43. data/lib/lhm/table_name.rb +23 -0
  44. data/lib/lhm/test_support.rb +35 -0
  45. data/lib/lhm/throttler/slave_lag.rb +162 -0
  46. data/lib/lhm/throttler/threads_running.rb +53 -0
  47. data/lib/lhm/throttler/time.rb +29 -0
  48. data/lib/lhm/throttler.rb +36 -0
  49. data/lib/lhm/timestamp.rb +11 -0
  50. data/lib/lhm/version.rb +6 -0
  51. data/lib/lhm-shopify.rb +1 -0
  52. data/lib/lhm.rb +156 -0
  53. data/scripts/helpers/wait-for-dbs.sh +21 -0
  54. data/scripts/mysql/reader/create_replication.sql +10 -0
  55. data/scripts/mysql/writer/create_test_db.sql +1 -0
  56. data/scripts/mysql/writer/create_users.sql +6 -0
  57. data/scripts/proxysql/proxysql.cnf +117 -0
  58. data/shipit.rubygems.yml +0 -0
  59. data/spec/.lhm.example +4 -0
  60. data/spec/README.md +58 -0
  61. data/spec/fixtures/bigint_table.ddl +4 -0
  62. data/spec/fixtures/composite_primary_key.ddl +6 -0
  63. data/spec/fixtures/composite_primary_key_dest.ddl +6 -0
  64. data/spec/fixtures/custom_primary_key.ddl +6 -0
  65. data/spec/fixtures/custom_primary_key_dest.ddl +6 -0
  66. data/spec/fixtures/destination.ddl +6 -0
  67. data/spec/fixtures/lines.ddl +7 -0
  68. data/spec/fixtures/origin.ddl +6 -0
  69. data/spec/fixtures/permissions.ddl +5 -0
  70. data/spec/fixtures/small_table.ddl +4 -0
  71. data/spec/fixtures/tracks.ddl +5 -0
  72. data/spec/fixtures/users.ddl +14 -0
  73. data/spec/fixtures/wo_id_int_column.ddl +6 -0
  74. data/spec/integration/atomic_switcher_spec.rb +129 -0
  75. data/spec/integration/chunk_insert_spec.rb +30 -0
  76. data/spec/integration/chunker_spec.rb +269 -0
  77. data/spec/integration/cleanup_spec.rb +147 -0
  78. data/spec/integration/database.yml +25 -0
  79. data/spec/integration/entangler_spec.rb +68 -0
  80. data/spec/integration/integration_helper.rb +252 -0
  81. data/spec/integration/invoker_spec.rb +33 -0
  82. data/spec/integration/lhm_spec.rb +659 -0
  83. data/spec/integration/lock_wait_timeout_spec.rb +30 -0
  84. data/spec/integration/locked_switcher_spec.rb +50 -0
  85. data/spec/integration/proxysql_spec.rb +34 -0
  86. data/spec/integration/sql_retry/db_connection_helper.rb +52 -0
  87. data/spec/integration/sql_retry/lock_wait_spec.rb +127 -0
  88. data/spec/integration/sql_retry/lock_wait_timeout_test_helper.rb +114 -0
  89. data/spec/integration/sql_retry/proxysql_helper.rb +22 -0
  90. data/spec/integration/sql_retry/retry_with_proxysql_spec.rb +109 -0
  91. data/spec/integration/table_spec.rb +83 -0
  92. data/spec/integration/toxiproxy_helper.rb +40 -0
  93. data/spec/test_helper.rb +69 -0
  94. data/spec/unit/atomic_switcher_spec.rb +29 -0
  95. data/spec/unit/chunk_finder_spec.rb +73 -0
  96. data/spec/unit/chunk_insert_spec.rb +67 -0
  97. data/spec/unit/chunker_spec.rb +176 -0
  98. data/spec/unit/connection_spec.rb +111 -0
  99. data/spec/unit/entangler_spec.rb +187 -0
  100. data/spec/unit/intersection_spec.rb +51 -0
  101. data/spec/unit/lhm_spec.rb +46 -0
  102. data/spec/unit/locked_switcher_spec.rb +46 -0
  103. data/spec/unit/migrator_spec.rb +144 -0
  104. data/spec/unit/printer_spec.rb +85 -0
  105. data/spec/unit/sql_helper_spec.rb +28 -0
  106. data/spec/unit/table_name_spec.rb +39 -0
  107. data/spec/unit/table_spec.rb +47 -0
  108. data/spec/unit/throttler/slave_lag_spec.rb +322 -0
  109. data/spec/unit/throttler/threads_running_spec.rb +64 -0
  110. data/spec/unit/throttler_spec.rb +124 -0
  111. data/spec/unit/unit_helper.rb +26 -0
  112. metadata +366 -0
@@ -0,0 +1,322 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../unit_helper'
2
+
3
+ require 'lhm/throttler/slave_lag'
4
+
5
+ describe Lhm::Throttler do
6
+ include UnitHelper
7
+
8
+ describe '#format_hosts' do
9
+ describe 'with only localhost hosts' do
10
+ it 'returns no hosts' do
11
+ assert_equal([], Lhm::Throttler.format_hosts(['localhost:1234', '127.0.0.1:5678']))
12
+ end
13
+ end
14
+
15
+ describe 'with only remote hosts' do
16
+ it 'returns remote hosts' do
17
+ assert_equal(['server.example.com', 'anotherserver.example.com'], Lhm::Throttler.format_hosts(['server.example.com:1234', 'anotherserver.example.com']))
18
+ end
19
+ end
20
+
21
+ describe 'with only nil hosts' do
22
+ it 'returns no hosts' do
23
+ assert_equal([], Lhm::Throttler.format_hosts([nil]))
24
+ end
25
+ end
26
+
27
+ describe 'with some nil hosts' do
28
+ it 'returns the remaining hosts' do
29
+ assert_equal(['server.example.com'], Lhm::Throttler.format_hosts([nil, 'server.example.com:1234']))
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ describe Lhm::Throttler::Slave do
36
+ include UnitHelper
37
+
38
+ before :each do
39
+ @logs = StringIO.new
40
+ Lhm.logger = Logger.new(@logs)
41
+
42
+ @dummy_mysql_client_config = lambda { { 'username' => 'user', 'password' => 'pw', 'database' => 'db' } }
43
+ end
44
+
45
+ describe "#client" do
46
+ before do
47
+ class TestMysql2Client
48
+ def initialize(config)
49
+ raise Mysql2::Error.new("connection error")
50
+ end
51
+ end
52
+ end
53
+
54
+ describe 'on connection error' do
55
+ it 'logs and returns nil' do
56
+ assert_nil(Lhm::Throttler::Slave.new('slave', @dummy_mysql_client_config).connection)
57
+
58
+ log_messages = @logs.string.lines
59
+ assert_equal(2, log_messages.length)
60
+ assert log_messages[0].include? "Connecting to slave on database: db"
61
+ assert log_messages[1].include? "Error connecting to slave: Unknown MySQL server host 'slave'"
62
+ end
63
+ end
64
+
65
+ describe 'with proper config' do
66
+ it "creates a new Mysql2::Client" do
67
+ expected_config = { username: 'user', password: 'pw', database: 'db', host: 'slave' }
68
+ Mysql2::Client.stubs(:new).with(expected_config).returns(mock())
69
+
70
+ assert Lhm::Throttler::Slave.new('slave', @dummy_mysql_client_config).connection
71
+ end
72
+ end
73
+
74
+ describe 'with active record config' do
75
+ it 'logs and creates client' do
76
+ active_record_config = { username: 'user', password: 'pw', database: 'db' }
77
+ if ActiveRecord::VERSION::MAJOR > 6 || ActiveRecord::VERSION::MAJOR == 6 && ActiveRecord::VERSION::MINOR >= 1
78
+ ActiveRecord::Base.stubs(:connection_pool).returns(stub(db_config: stub(configuration_hash: active_record_config)))
79
+ else
80
+ ActiveRecord::Base.stubs(:connection_pool).returns(stub(spec: stub(config: active_record_config)))
81
+ end
82
+
83
+ Mysql2::Client.stubs(:new).returns(mock())
84
+
85
+ assert Lhm::Throttler::Slave.new('slave').connection
86
+
87
+ log_messages = @logs.string.lines
88
+ assert_equal(1, log_messages.length)
89
+ assert log_messages[0].include? "Connecting to slave on database: db"
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "#connection" do
95
+ before do
96
+ class Connection
97
+ def self.query(query)
98
+ if query == Lhm::Throttler::Slave::SQL_SELECT_MAX_SLAVE_LAG
99
+ [{ 'Seconds_Behind_Master' => 20 }]
100
+ elsif query == Lhm::Throttler::Slave::SQL_SELECT_SLAVE_HOSTS
101
+ [{ 'host' => '1.1.1.1:80' }]
102
+ end
103
+ end
104
+ end
105
+
106
+ @slave = Lhm::Throttler::Slave.new('slave', @dummy_mysql_client_config)
107
+ @slave.instance_variable_set(:@connection, Connection)
108
+
109
+ class StoppedConnection
110
+ def self.query(query)
111
+ [{ 'Seconds_Behind_Master' => nil }]
112
+ end
113
+ end
114
+
115
+ @stopped_slave = Lhm::Throttler::Slave.new('stopped_slave', @dummy_mysql_client_config)
116
+ @stopped_slave.instance_variable_set(:@connection, StoppedConnection)
117
+ end
118
+
119
+ describe "#lag" do
120
+ it "returns the slave lag" do
121
+ assert_equal(20, @slave.lag)
122
+ end
123
+ end
124
+
125
+ describe "#lag with a stopped slave" do
126
+ it "returns 0 slave lag" do
127
+ assert_equal(0, @stopped_slave.lag)
128
+ end
129
+ end
130
+
131
+ describe "#slave_hosts" do
132
+ it "returns the hosts" do
133
+ assert_equal(['1.1.1.1'], @slave.slave_hosts)
134
+ end
135
+ end
136
+
137
+ describe "#lag on connection error" do
138
+ it "logs and returns 0 slave lag" do
139
+ client = mock()
140
+ client.stubs(:query).raises(Mysql2::Error, "Can't connect to MySQL server")
141
+ Lhm::Throttler::Slave.any_instance.stubs(:client).returns(client)
142
+ Lhm::Throttler::Slave.any_instance.stubs(:config).returns([])
143
+
144
+ slave = Lhm::Throttler::Slave.new('slave', @dummy_mysql_client_config)
145
+ Logger.any_instance.expects(:info).with("Unable to connect and/or query slave: Can't connect to MySQL server")
146
+ assert_equal(0, slave.lag)
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ describe Lhm::Throttler::SlaveLag do
153
+ include UnitHelper
154
+
155
+ before :each do
156
+ @throttler = Lhm::Throttler::SlaveLag.new
157
+ end
158
+
159
+ describe '#throttle_seconds' do
160
+ describe 'with no slave lag' do
161
+ before do
162
+ def @throttler.max_current_slave_lag
163
+ 0
164
+ end
165
+ end
166
+
167
+ it 'does not alter the currently set timeout' do
168
+ timeout = @throttler.timeout_seconds
169
+ assert_equal(timeout, @throttler.send(:throttle_seconds))
170
+ end
171
+ end
172
+
173
+ describe 'with a large slave lag' do
174
+ before do
175
+ def @throttler.max_current_slave_lag
176
+ 100
177
+ end
178
+ end
179
+
180
+ it 'doubles the currently set timeout' do
181
+ timeout = @throttler.timeout_seconds
182
+ assert_equal(timeout * 2, @throttler.send(:throttle_seconds))
183
+ end
184
+
185
+ it 'does not increase the timeout past the maximum' do
186
+ @throttler.timeout_seconds = Lhm::Throttler::SlaveLag::MAX_TIMEOUT
187
+ assert_equal(Lhm::Throttler::SlaveLag::MAX_TIMEOUT, @throttler.send(:throttle_seconds))
188
+ end
189
+ end
190
+
191
+ describe 'with no slave lag after it has previously been increased' do
192
+ before do
193
+ def @throttler.max_current_slave_lag
194
+ 0
195
+ end
196
+ end
197
+
198
+ it 'halves the currently set timeout' do
199
+ @throttler.timeout_seconds *= 2 * 2
200
+ timeout = @throttler.timeout_seconds
201
+ assert_equal(timeout / 2, @throttler.send(:throttle_seconds))
202
+ end
203
+
204
+ it 'does not decrease the timeout past the minimum on repeated runs' do
205
+ @throttler.timeout_seconds = Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT * 2
206
+ assert_equal(Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT, @throttler.send(:throttle_seconds))
207
+ assert_equal(Lhm::Throttler::SlaveLag::INITIAL_TIMEOUT, @throttler.send(:throttle_seconds))
208
+ end
209
+ end
210
+ end
211
+
212
+ describe '#max_current_slave_lag' do
213
+ describe 'with multiple slaves' do
214
+ it 'returns the largest amount of lag' do
215
+ slave1 = mock()
216
+ slave2 = mock()
217
+ slave1.stubs(:lag).returns(5)
218
+ slave2.stubs(:lag).returns(0)
219
+ Lhm::Throttler::SlaveLag.any_instance.stubs(:slaves).returns([slave1, slave2])
220
+ assert_equal 5, @throttler.send(:max_current_slave_lag)
221
+ end
222
+ end
223
+
224
+ describe 'with MySQL stopped on the slave' do
225
+ it 'assumes 0 slave lag' do
226
+ client = mock()
227
+ client.stubs(:query).raises(Mysql2::Error, "Can't connect to MySQL server")
228
+ Lhm::Throttler::Slave.any_instance.stubs(:client).returns(client)
229
+
230
+ Lhm::Throttler::Slave.any_instance.stubs(:prepare_connection_config).returns([])
231
+ Lhm::Throttler::Slave.any_instance.stubs(:slave_hosts).returns(['1.1.1.2'])
232
+ @throttler.stubs(:master_slave_hosts).returns(['1.1.1.1'])
233
+
234
+ assert_equal 0, @throttler.send(:max_current_slave_lag)
235
+ end
236
+ end
237
+ end
238
+
239
+ describe '#get_slaves' do
240
+ describe 'with no slaves' do
241
+ before do
242
+ def @throttler.master_slave_hosts
243
+ []
244
+ end
245
+ end
246
+
247
+ it 'returns no slaves' do
248
+ assert_equal([], @throttler.send(:get_slaves))
249
+ end
250
+ end
251
+
252
+ describe 'with multiple slaves' do
253
+ before do
254
+ class TestSlave
255
+ attr_reader :host, :connection
256
+
257
+ def initialize(host, _)
258
+ @host = host
259
+ @connection = 'conn' if @host
260
+ end
261
+
262
+ def slave_hosts
263
+ if @host == '1.1.1.1'
264
+ ['1.1.1.2', '1.1.1.3']
265
+ else
266
+ [nil]
267
+ end
268
+ end
269
+ end
270
+
271
+ @create_slave = lambda { |host, config|
272
+ TestSlave.new(host, config)
273
+ }
274
+ end
275
+
276
+ describe 'without the :check_only option' do
277
+ before do
278
+ def @throttler.master_slave_hosts
279
+ ['1.1.1.1', '1.1.1.4']
280
+ end
281
+ end
282
+
283
+ it 'returns the slave instances' do
284
+ Lhm::Throttler::Slave.stubs(:new).returns(@create_slave) do
285
+ assert_equal(["1.1.1.4", "1.1.1.1", "1.1.1.3", "1.1.1.2"], @throttler.send(:get_slaves).map(&:host))
286
+ end
287
+ end
288
+ end
289
+
290
+ describe 'with the :check_only option' do
291
+ describe 'with a callable argument' do
292
+ before do
293
+ check_only = lambda { { 'host' => '1.1.1.3' } }
294
+ @throttler = Lhm::Throttler::SlaveLag.new :check_only => check_only
295
+ end
296
+
297
+ it 'returns only that single slave' do
298
+ Lhm::Throttler::Slave.stubs(:new).returns(@create_slave) do
299
+ assert_equal ['1.1.1.3'], @throttler.send(:get_slaves).map(&:host)
300
+ end
301
+ end
302
+ end
303
+
304
+ describe 'with a non-callable argument' do
305
+ before do
306
+ @throttler = Lhm::Throttler::SlaveLag.new :check_only => 'I cannot be called'
307
+
308
+ def @throttler.master_slave_hosts
309
+ ['1.1.1.1', '1.1.1.4']
310
+ end
311
+ end
312
+
313
+ it 'returns all the slave instances' do
314
+ Lhm::Throttler::Slave.stubs(:new).returns(@create_slave) do
315
+ assert_equal(["1.1.1.4", "1.1.1.1", "1.1.1.3", "1.1.1.2"], @throttler.send(:get_slaves).map(&:host))
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../unit_helper'
2
+
3
+ require 'lhm/throttler/threads_running'
4
+
5
+ describe Lhm::Throttler::ThreadsRunning do
6
+ include UnitHelper
7
+
8
+ before :each do
9
+ @throttler = Lhm::Throttler::ThreadsRunning.new
10
+ end
11
+
12
+ describe '#throttle_seconds' do
13
+ describe 'with no mysql activity' do
14
+ before do
15
+ def @throttler.threads_running
16
+ 0
17
+ end
18
+ end
19
+
20
+ it 'does not alter the currently set timeout' do
21
+ timeout = @throttler.timeout_seconds
22
+ assert_equal(timeout, @throttler.send(:throttle_seconds))
23
+ end
24
+ end
25
+
26
+ describe 'with an overloaded mysql' do
27
+ before do
28
+ def @throttler.threads_running
29
+ 100
30
+ end
31
+ end
32
+
33
+ it 'doubles the currently set timeout' do
34
+ timeout = @throttler.timeout_seconds
35
+ assert_equal(timeout * 2, @throttler.send(:throttle_seconds))
36
+ end
37
+
38
+ it 'does not increase the timeout past the maximum' do
39
+ @throttler.timeout_seconds = @throttler.max_timeout_seconds
40
+ assert_equal(@throttler.max_timeout_seconds, @throttler.send(:throttle_seconds))
41
+ end
42
+ end
43
+
44
+ describe 'with an idle mysql after it has previously been busy' do
45
+ before do
46
+ def @throttler.threads_running
47
+ 0
48
+ end
49
+ end
50
+
51
+ it 'halves the currently set timeout' do
52
+ @throttler.timeout_seconds *= 2 * 2
53
+ timeout = @throttler.timeout_seconds
54
+ assert_equal(timeout / 2, @throttler.send(:throttle_seconds))
55
+ end
56
+
57
+ it 'does not decrease the timeout past the minimum on repeated runs' do
58
+ @throttler.timeout_seconds = @throttler.initial_timeout_seconds * 2
59
+ assert_equal(@throttler.initial_timeout_seconds, @throttler.send(:throttle_seconds))
60
+ assert_equal(@throttler.initial_timeout_seconds, @throttler.send(:throttle_seconds))
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,124 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/unit_helper'
2
+
3
+ require 'lhm/throttler'
4
+
5
+ describe Lhm::Throttler do
6
+ include UnitHelper
7
+
8
+ before :each do
9
+ @mock = Class.new do
10
+ extend Lhm::Throttler
11
+ end
12
+
13
+ @conn = Class.new do
14
+ def execute
15
+ end
16
+ end
17
+ end
18
+
19
+ describe '#setup_throttler' do
20
+ describe 'when passing a time_throttler key' do
21
+ before do
22
+ @mock.setup_throttler(:time_throttler, delay: 2)
23
+ end
24
+
25
+ it 'instantiates the time throttle' do
26
+ value(@mock.throttler.class).must_equal Lhm::Throttler::Time
27
+ end
28
+
29
+ it 'returns 2 seconds as time' do
30
+ value(@mock.throttler.timeout_seconds).must_equal 2
31
+ end
32
+ end
33
+
34
+ describe 'when passing a slave_lag_throttler key' do
35
+ before do
36
+ @mock.setup_throttler(:slave_lag_throttler, allowed_lag: 20)
37
+ end
38
+
39
+ it 'instantiates the slave_lag throttle' do
40
+ value(@mock.throttler.class).must_equal Lhm::Throttler::SlaveLag
41
+ end
42
+
43
+ it 'returns 20 seconds as allowed_lag' do
44
+ value(@mock.throttler.allowed_lag).must_equal 20
45
+ end
46
+ end
47
+
48
+ describe 'when passing a time_throttler instance' do
49
+
50
+ before do
51
+ @instance = Class.new(Lhm::Throttler::Time) do
52
+ def timeout_seconds
53
+ 0
54
+ end
55
+ end.new
56
+
57
+ @mock.setup_throttler(@instance)
58
+ end
59
+
60
+ it 'returns the instace given' do
61
+ value(@mock.throttler).must_equal @instance
62
+ end
63
+
64
+ it 'returns 0 seconds as time' do
65
+ value(@mock.throttler.timeout_seconds).must_equal 0
66
+ end
67
+ end
68
+
69
+ describe 'when passing a slave_lag_throttler instance' do
70
+
71
+ before do
72
+ @instance = Lhm::Throttler::SlaveLag.new
73
+ def @instance.timeout_seconds
74
+ 0
75
+ end
76
+
77
+ @mock.setup_throttler(@instance)
78
+ end
79
+
80
+ it 'returns the instace given' do
81
+ value(@mock.throttler).must_equal @instance
82
+ end
83
+
84
+ it 'returns 0 seconds as time' do
85
+ value(@mock.throttler.timeout_seconds).must_equal 0
86
+ end
87
+ end
88
+
89
+ describe 'when passing a time_throttler class' do
90
+
91
+ before do
92
+ @klass = Class.new(Lhm::Throttler::Time)
93
+ @mock.setup_throttler(@klass)
94
+ end
95
+
96
+ it 'has the same class as given' do
97
+ value(@mock.throttler.class).must_equal @klass
98
+ end
99
+ end
100
+
101
+ describe 'when passing a slave_lag_throttler class' do
102
+
103
+ before do
104
+ @klass = Class.new(Lhm::Throttler::SlaveLag)
105
+ @mock.setup_throttler(@klass)
106
+ end
107
+
108
+ it 'has the same class as given' do
109
+ value(@mock.throttler.class).must_equal @klass
110
+ end
111
+ end
112
+ end
113
+
114
+ describe '#throttler' do
115
+
116
+ it 'returns the default Time based' do
117
+ value(@mock.throttler.class).must_equal Lhm::Throttler::Time
118
+ end
119
+
120
+ it 'should default to 100 milliseconds' do
121
+ value(@mock.throttler.timeout_seconds).must_equal 0.1
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2011 - 2013, SoundCloud Ltd., Rany Keddo, Tobias Bielohlawek, Tobias
2
+ # Schmidt
3
+ require 'test_helper'
4
+
5
+ module UnitHelper
6
+ LOG_EXPRESSION = /([\w]+),\s+\[([^\]\s]+)\s+#([^\]]+)]\s+(\w+)\s+--\s+(\w+)?:\s+(.+)/
7
+
8
+ def fixture(name)
9
+ File.read $fixtures.join(name)
10
+ end
11
+
12
+ def strip(sql)
13
+ sql.strip.gsub(/\n */, "\n")
14
+ end
15
+
16
+ def log_expression_message(msg)
17
+ msg.gsub(LOG_EXPRESSION) do |match|
18
+ severity = $1
19
+ date = $2
20
+ pid = $3
21
+ label = $4
22
+ app = $5
23
+ message = $6
24
+ end
25
+ end
26
+ end