lhm-teak 3.6.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 (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