sr-sidekiq 4.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/3.0-Upgrade.md +70 -0
  4. data/4.0-Upgrade.md +50 -0
  5. data/COMM-LICENSE (sidekiq) +95 -0
  6. data/Changes.md +1241 -0
  7. data/Ent-Changes.md +112 -0
  8. data/Gemfile +29 -0
  9. data/LICENSE (sidekiq) +9 -0
  10. data/LICENSE (sr-sidekiq) +5 -0
  11. data/Pro-2.0-Upgrade.md +138 -0
  12. data/Pro-3.0-Upgrade.md +44 -0
  13. data/Pro-Changes.md +539 -0
  14. data/README.md +8 -0
  15. data/Rakefile +9 -0
  16. data/bin/sidekiq +18 -0
  17. data/bin/sidekiqctl +99 -0
  18. data/bin/sidekiqload +167 -0
  19. data/code_of_conduct.md +50 -0
  20. data/lib/generators/sidekiq/templates/worker.rb.erb +9 -0
  21. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +6 -0
  22. data/lib/generators/sidekiq/templates/worker_test.rb.erb +8 -0
  23. data/lib/generators/sidekiq/worker_generator.rb +49 -0
  24. data/lib/sidekiq.rb +237 -0
  25. data/lib/sidekiq/api.rb +844 -0
  26. data/lib/sidekiq/cli.rb +389 -0
  27. data/lib/sidekiq/client.rb +260 -0
  28. data/lib/sidekiq/core_ext.rb +106 -0
  29. data/lib/sidekiq/exception_handler.rb +31 -0
  30. data/lib/sidekiq/extensions/action_mailer.rb +57 -0
  31. data/lib/sidekiq/extensions/active_record.rb +40 -0
  32. data/lib/sidekiq/extensions/class_methods.rb +40 -0
  33. data/lib/sidekiq/extensions/generic_proxy.rb +25 -0
  34. data/lib/sidekiq/fetch.rb +81 -0
  35. data/lib/sidekiq/launcher.rb +160 -0
  36. data/lib/sidekiq/logging.rb +106 -0
  37. data/lib/sidekiq/manager.rb +137 -0
  38. data/lib/sidekiq/middleware/chain.rb +150 -0
  39. data/lib/sidekiq/middleware/i18n.rb +42 -0
  40. data/lib/sidekiq/middleware/server/active_record.rb +13 -0
  41. data/lib/sidekiq/middleware/server/logging.rb +40 -0
  42. data/lib/sidekiq/middleware/server/retry_jobs.rb +205 -0
  43. data/lib/sidekiq/paginator.rb +43 -0
  44. data/lib/sidekiq/processor.rb +186 -0
  45. data/lib/sidekiq/rails.rb +39 -0
  46. data/lib/sidekiq/redis_connection.rb +97 -0
  47. data/lib/sidekiq/scheduled.rb +146 -0
  48. data/lib/sidekiq/testing.rb +316 -0
  49. data/lib/sidekiq/testing/inline.rb +29 -0
  50. data/lib/sidekiq/util.rb +62 -0
  51. data/lib/sidekiq/version.rb +4 -0
  52. data/lib/sidekiq/web.rb +278 -0
  53. data/lib/sidekiq/web_helpers.rb +255 -0
  54. data/lib/sidekiq/worker.rb +121 -0
  55. data/sidekiq.gemspec +26 -0
  56. data/sr-sidekiq-4.1.3.gem +0 -0
  57. data/sr-sidekiq-4.1.4.gem +0 -0
  58. data/sr-sidekiq-4.1.5.gem +0 -0
  59. data/test/config.yml +9 -0
  60. data/test/env_based_config.yml +11 -0
  61. data/test/fake_env.rb +1 -0
  62. data/test/fixtures/en.yml +2 -0
  63. data/test/helper.rb +75 -0
  64. data/test/test_actors.rb +138 -0
  65. data/test/test_api.rb +528 -0
  66. data/test/test_cli.rb +406 -0
  67. data/test/test_client.rb +262 -0
  68. data/test/test_exception_handler.rb +56 -0
  69. data/test/test_extensions.rb +127 -0
  70. data/test/test_fetch.rb +50 -0
  71. data/test/test_launcher.rb +85 -0
  72. data/test/test_logging.rb +35 -0
  73. data/test/test_manager.rb +50 -0
  74. data/test/test_middleware.rb +158 -0
  75. data/test/test_processor.rb +201 -0
  76. data/test/test_rails.rb +22 -0
  77. data/test/test_redis_connection.rb +127 -0
  78. data/test/test_retry.rb +326 -0
  79. data/test/test_retry_exhausted.rb +149 -0
  80. data/test/test_scheduled.rb +115 -0
  81. data/test/test_scheduling.rb +50 -0
  82. data/test/test_sidekiq.rb +107 -0
  83. data/test/test_testing.rb +143 -0
  84. data/test/test_testing_fake.rb +357 -0
  85. data/test/test_testing_inline.rb +94 -0
  86. data/test/test_util.rb +13 -0
  87. data/test/test_web.rb +614 -0
  88. data/test/test_web_helpers.rb +54 -0
  89. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  90. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  91. data/web/assets/images/favicon.ico +0 -0
  92. data/web/assets/images/logo.png +0 -0
  93. data/web/assets/images/status-sd8051fd480.png +0 -0
  94. data/web/assets/images/status/active.png +0 -0
  95. data/web/assets/images/status/idle.png +0 -0
  96. data/web/assets/javascripts/application.js +88 -0
  97. data/web/assets/javascripts/dashboard.js +300 -0
  98. data/web/assets/javascripts/locales/README.md +27 -0
  99. data/web/assets/javascripts/locales/jquery.timeago.ar.js +96 -0
  100. data/web/assets/javascripts/locales/jquery.timeago.bg.js +18 -0
  101. data/web/assets/javascripts/locales/jquery.timeago.bs.js +49 -0
  102. data/web/assets/javascripts/locales/jquery.timeago.ca.js +18 -0
  103. data/web/assets/javascripts/locales/jquery.timeago.cs.js +18 -0
  104. data/web/assets/javascripts/locales/jquery.timeago.cy.js +20 -0
  105. data/web/assets/javascripts/locales/jquery.timeago.da.js +18 -0
  106. data/web/assets/javascripts/locales/jquery.timeago.de.js +18 -0
  107. data/web/assets/javascripts/locales/jquery.timeago.el.js +18 -0
  108. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +20 -0
  109. data/web/assets/javascripts/locales/jquery.timeago.en.js +20 -0
  110. data/web/assets/javascripts/locales/jquery.timeago.es.js +18 -0
  111. data/web/assets/javascripts/locales/jquery.timeago.et.js +18 -0
  112. data/web/assets/javascripts/locales/jquery.timeago.fa.js +22 -0
  113. data/web/assets/javascripts/locales/jquery.timeago.fi.js +28 -0
  114. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +16 -0
  115. data/web/assets/javascripts/locales/jquery.timeago.fr.js +17 -0
  116. data/web/assets/javascripts/locales/jquery.timeago.he.js +18 -0
  117. data/web/assets/javascripts/locales/jquery.timeago.hr.js +49 -0
  118. data/web/assets/javascripts/locales/jquery.timeago.hu.js +18 -0
  119. data/web/assets/javascripts/locales/jquery.timeago.hy.js +18 -0
  120. data/web/assets/javascripts/locales/jquery.timeago.id.js +18 -0
  121. data/web/assets/javascripts/locales/jquery.timeago.it.js +16 -0
  122. data/web/assets/javascripts/locales/jquery.timeago.ja.js +19 -0
  123. data/web/assets/javascripts/locales/jquery.timeago.ko.js +17 -0
  124. data/web/assets/javascripts/locales/jquery.timeago.lt.js +20 -0
  125. data/web/assets/javascripts/locales/jquery.timeago.mk.js +20 -0
  126. data/web/assets/javascripts/locales/jquery.timeago.nl.js +20 -0
  127. data/web/assets/javascripts/locales/jquery.timeago.no.js +18 -0
  128. data/web/assets/javascripts/locales/jquery.timeago.pl.js +31 -0
  129. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +16 -0
  130. data/web/assets/javascripts/locales/jquery.timeago.pt.js +16 -0
  131. data/web/assets/javascripts/locales/jquery.timeago.ro.js +18 -0
  132. data/web/assets/javascripts/locales/jquery.timeago.rs.js +49 -0
  133. data/web/assets/javascripts/locales/jquery.timeago.ru.js +34 -0
  134. data/web/assets/javascripts/locales/jquery.timeago.sk.js +18 -0
  135. data/web/assets/javascripts/locales/jquery.timeago.sl.js +44 -0
  136. data/web/assets/javascripts/locales/jquery.timeago.sv.js +18 -0
  137. data/web/assets/javascripts/locales/jquery.timeago.th.js +20 -0
  138. data/web/assets/javascripts/locales/jquery.timeago.tr.js +16 -0
  139. data/web/assets/javascripts/locales/jquery.timeago.uk.js +34 -0
  140. data/web/assets/javascripts/locales/jquery.timeago.uz.js +19 -0
  141. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +20 -0
  142. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +20 -0
  143. data/web/assets/stylesheets/application.css +754 -0
  144. data/web/assets/stylesheets/bootstrap.css +9 -0
  145. data/web/locales/cs.yml +78 -0
  146. data/web/locales/da.yml +68 -0
  147. data/web/locales/de.yml +69 -0
  148. data/web/locales/el.yml +68 -0
  149. data/web/locales/en.yml +79 -0
  150. data/web/locales/es.yml +69 -0
  151. data/web/locales/fr.yml +78 -0
  152. data/web/locales/hi.yml +75 -0
  153. data/web/locales/it.yml +69 -0
  154. data/web/locales/ja.yml +78 -0
  155. data/web/locales/ko.yml +68 -0
  156. data/web/locales/nb.yml +77 -0
  157. data/web/locales/nl.yml +68 -0
  158. data/web/locales/pl.yml +59 -0
  159. data/web/locales/pt-br.yml +68 -0
  160. data/web/locales/pt.yml +67 -0
  161. data/web/locales/ru.yml +78 -0
  162. data/web/locales/sv.yml +68 -0
  163. data/web/locales/ta.yml +75 -0
  164. data/web/locales/uk.yml +76 -0
  165. data/web/locales/zh-cn.yml +68 -0
  166. data/web/locales/zh-tw.yml +68 -0
  167. data/web/views/_footer.erb +17 -0
  168. data/web/views/_job_info.erb +88 -0
  169. data/web/views/_nav.erb +66 -0
  170. data/web/views/_paging.erb +23 -0
  171. data/web/views/_poll_js.erb +5 -0
  172. data/web/views/_poll_link.erb +7 -0
  173. data/web/views/_status.erb +4 -0
  174. data/web/views/_summary.erb +40 -0
  175. data/web/views/busy.erb +94 -0
  176. data/web/views/dashboard.erb +75 -0
  177. data/web/views/dead.erb +34 -0
  178. data/web/views/layout.erb +32 -0
  179. data/web/views/morgue.erb +71 -0
  180. data/web/views/queue.erb +45 -0
  181. data/web/views/queues.erb +28 -0
  182. data/web/views/retries.erb +74 -0
  183. data/web/views/retry.erb +34 -0
  184. data/web/views/scheduled.erb +54 -0
  185. data/web/views/scheduled_job_info.erb +8 -0
  186. metadata +408 -0
data/test/test_cli.rb ADDED
@@ -0,0 +1,406 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'helper'
3
+ require 'sidekiq/cli'
4
+ require 'tempfile'
5
+
6
+ class Sidekiq::CLI
7
+ def die(code)
8
+ @code = code
9
+ end
10
+
11
+ def valid?
12
+ !@code
13
+ end
14
+ end
15
+
16
+ class TestCli < Sidekiq::Test
17
+ describe 'CLI#parse' do
18
+
19
+ before do
20
+ @cli = Sidekiq::CLI.new
21
+ @opts = Sidekiq.options.dup
22
+ end
23
+
24
+ after do
25
+ Sidekiq.options = @opts
26
+ end
27
+
28
+ it 'does not require the specified Ruby code' do
29
+ @cli.parse(['sidekiq', '-r', './test/fake_env.rb'])
30
+ refute($LOADED_FEATURES.any? { |x| x =~ /fake_env/ })
31
+ assert @cli.valid?
32
+ end
33
+
34
+ it 'does not boot rails' do
35
+ refute defined?(::Rails::Application)
36
+ @cli.parse(['sidekiq', '-r', './myapp'])
37
+ refute defined?(::Rails::Application)
38
+ end
39
+
40
+ it 'changes concurrency' do
41
+ @cli.parse(['sidekiq', '-c', '60', '-r', './test/fake_env.rb'])
42
+ assert_equal 60, Sidekiq.options[:concurrency]
43
+ end
44
+
45
+ it 'changes queues' do
46
+ @cli.parse(['sidekiq', '-q', 'foo', '-r', './test/fake_env.rb'])
47
+ assert_equal ['foo'], Sidekiq.options[:queues]
48
+ end
49
+
50
+ it 'accepts a process index' do
51
+ @cli.parse(['sidekiq', '-i', '7', '-r', './test/fake_env.rb'])
52
+ assert_equal 7, Sidekiq.options[:index]
53
+ end
54
+
55
+ it 'accepts a stringy process index' do
56
+ @cli.parse(['sidekiq', '-i', 'worker.7', '-r', './test/fake_env.rb'])
57
+ assert_equal 7, Sidekiq.options[:index]
58
+ end
59
+
60
+ it 'sets strictly ordered queues if weights are not present' do
61
+ @cli.parse(['sidekiq', '-q', 'foo', '-q', 'bar', '-r', './test/fake_env.rb'])
62
+ assert_equal true, !!Sidekiq.options[:strict]
63
+ end
64
+
65
+ it 'does not set strictly ordered queues if weights are present' do
66
+ @cli.parse(['sidekiq', '-q', 'foo,3', '-r', './test/fake_env.rb'])
67
+ assert_equal false, !!Sidekiq.options[:strict]
68
+ end
69
+
70
+ it 'does not set strictly ordered queues if weights are present with multiple queues' do
71
+ @cli.parse(['sidekiq', '-q', 'foo,3', '-q', 'bar', '-r', './test/fake_env.rb'])
72
+ assert_equal false, !!Sidekiq.options[:strict]
73
+ end
74
+
75
+ it 'changes timeout' do
76
+ @cli.parse(['sidekiq', '-t', '30', '-r', './test/fake_env.rb'])
77
+ assert_equal 30, Sidekiq.options[:timeout]
78
+ end
79
+
80
+ it 'handles multiple queues with weights' do
81
+ @cli.parse(['sidekiq', '-q', 'foo,3', '-q', 'bar', '-r', './test/fake_env.rb'])
82
+ assert_equal %w(foo foo foo bar), Sidekiq.options[:queues]
83
+ end
84
+
85
+ it 'handles queues with multi-word names' do
86
+ @cli.parse(['sidekiq', '-q', 'queue_one', '-q', 'queue-two', '-r', './test/fake_env.rb'])
87
+ assert_equal %w(queue_one queue-two), Sidekiq.options[:queues]
88
+ end
89
+
90
+ it 'handles queues with dots in the name' do
91
+ @cli.parse(['sidekiq', '-q', 'foo.bar', '-r', './test/fake_env.rb'])
92
+ assert_equal ['foo.bar'], Sidekiq.options[:queues]
93
+ end
94
+
95
+ it 'sets verbose' do
96
+ old = Sidekiq.logger.level
97
+ @cli.parse(['sidekiq', '-v', '-r', './test/fake_env.rb'])
98
+ assert_equal Logger::DEBUG, Sidekiq.logger.level
99
+ # If we leave the logger at DEBUG it'll add a lot of noise to the test output
100
+ Sidekiq.options.delete(:verbose)
101
+ Sidekiq.logger.level = old
102
+ end
103
+
104
+ describe 'with logfile' do
105
+ before do
106
+ @old_logger = Sidekiq.logger
107
+ @tmp_log_path = '/tmp/sidekiq.log'
108
+ end
109
+
110
+ after do
111
+ Sidekiq.logger = @old_logger
112
+ Sidekiq.options.delete(:logfile)
113
+ File.unlink @tmp_log_path if File.exist?(@tmp_log_path)
114
+ end
115
+
116
+ it 'sets the logfile path' do
117
+ @cli.parse(['sidekiq', '-L', @tmp_log_path, '-r', './test/fake_env.rb'])
118
+
119
+ assert_equal @tmp_log_path, Sidekiq.options[:logfile]
120
+ end
121
+
122
+ it 'creates and writes to a logfile' do
123
+ @cli.parse(['sidekiq', '-L', @tmp_log_path, '-r', './test/fake_env.rb'])
124
+
125
+ Sidekiq.logger.info('test message')
126
+
127
+ assert_match(/test message/, File.read(@tmp_log_path), "didn't include the log message")
128
+ end
129
+
130
+ it 'appends messages to a logfile' do
131
+ File.open(@tmp_log_path, 'w') do |f|
132
+ f.puts 'already existent log message'
133
+ end
134
+
135
+ @cli.parse(['sidekiq', '-L', @tmp_log_path, '-r', './test/fake_env.rb'])
136
+
137
+ Sidekiq.logger.info('test message')
138
+
139
+ log_file_content = File.read(@tmp_log_path)
140
+ assert_match(/already existent/, log_file_content, "didn't include the old message")
141
+ assert_match(/test message/, log_file_content, "didn't include the new message")
142
+ end
143
+ end
144
+
145
+ describe 'with pidfile' do
146
+ before do
147
+ @tmp_file = Tempfile.new('sidekiq-test')
148
+ @tmp_path = @tmp_file.path
149
+ @tmp_file.close!
150
+
151
+ @cli.parse(['sidekiq', '-P', @tmp_path, '-r', './test/fake_env.rb'])
152
+ end
153
+
154
+ after do
155
+ File.unlink @tmp_path if File.exist? @tmp_path
156
+ end
157
+
158
+ it 'sets pidfile path' do
159
+ assert_equal @tmp_path, Sidekiq.options[:pidfile]
160
+ end
161
+
162
+ it 'writes pidfile' do
163
+ assert_equal File.read(@tmp_path).strip.to_i, Process.pid
164
+ end
165
+ end
166
+
167
+ describe 'with config file' do
168
+ before do
169
+ @cli.parse(['sidekiq', '-C', './test/config.yml'])
170
+ end
171
+
172
+ it 'parses as expected' do
173
+ assert_equal './test/config.yml', Sidekiq.options[:config_file]
174
+ refute Sidekiq.options[:verbose]
175
+ assert_equal './test/fake_env.rb', Sidekiq.options[:require]
176
+ assert_equal nil, Sidekiq.options[:environment]
177
+ assert_equal 50, Sidekiq.options[:concurrency]
178
+ assert_equal '/tmp/sidekiq-config-test.pid', Sidekiq.options[:pidfile]
179
+ assert_equal '/tmp/sidekiq.log', Sidekiq.options[:logfile]
180
+ assert_equal 2, Sidekiq.options[:queues].count { |q| q == 'very_often' }
181
+ assert_equal 1, Sidekiq.options[:queues].count { |q| q == 'seldom' }
182
+ end
183
+ end
184
+
185
+ describe 'with env based config file' do
186
+ before do
187
+ @cli.parse(['sidekiq', '-e', 'staging', '-C', './test/env_based_config.yml'])
188
+ end
189
+
190
+ it 'parses as expected' do
191
+ assert_equal './test/env_based_config.yml', Sidekiq.options[:config_file]
192
+ refute Sidekiq.options[:verbose]
193
+ assert_equal './test/fake_env.rb', Sidekiq.options[:require]
194
+ assert_equal 'staging', Sidekiq.options[:environment]
195
+ assert_equal 5, Sidekiq.options[:concurrency]
196
+ assert_equal '/tmp/sidekiq-config-test.pid', Sidekiq.options[:pidfile]
197
+ assert_equal '/tmp/sidekiq.log', Sidekiq.options[:logfile]
198
+ assert_equal 2, Sidekiq.options[:queues].count { |q| q == 'very_often' }
199
+ assert_equal 1, Sidekiq.options[:queues].count { |q| q == 'seldom' }
200
+ end
201
+ end
202
+
203
+ describe 'with an empty config file' do
204
+ before do
205
+ @tmp_file = Tempfile.new('sidekiq-test')
206
+ @tmp_path = @tmp_file.path
207
+ @tmp_file.close!
208
+ end
209
+
210
+ after do
211
+ File.unlink @tmp_path if File.exist? @tmp_path
212
+ end
213
+
214
+ it 'takes a path' do
215
+ @cli.parse(['sidekiq', '-C', @tmp_path])
216
+ assert_equal @tmp_path, Sidekiq.options[:config_file]
217
+ end
218
+
219
+ it 'should have an identical options hash, except for config_file' do
220
+ @cli.parse(['sidekiq'])
221
+ old_options = Sidekiq.options.clone
222
+
223
+ @cli.parse(['sidekiq', '-C', @tmp_path])
224
+ new_options = Sidekiq.options.clone
225
+ refute_equal old_options, new_options
226
+
227
+ new_options.delete(:config_file)
228
+ assert_equal old_options, new_options
229
+ end
230
+ end
231
+
232
+ describe 'with config file and flags' do
233
+ before do
234
+ # We need an actual file here.
235
+ @tmp_lib_path = '/tmp/require-me.rb'
236
+ File.open(@tmp_lib_path, 'w') do |f|
237
+ f.puts "# do work"
238
+ end
239
+
240
+ @tmp_file = Tempfile.new('sidekiqr')
241
+ @tmp_path = @tmp_file.path
242
+ @tmp_file.close!
243
+
244
+ @cli.parse(['sidekiq',
245
+ '-C', './test/config.yml',
246
+ '-e', 'snoop',
247
+ '-c', '100',
248
+ '-r', @tmp_lib_path,
249
+ '-P', @tmp_path,
250
+ '-q', 'often,7',
251
+ '-q', 'seldom,3'])
252
+ end
253
+
254
+ after do
255
+ File.unlink @tmp_lib_path if File.exist? @tmp_lib_path
256
+ File.unlink @tmp_path if File.exist? @tmp_path
257
+ end
258
+
259
+ it 'gives the expected options' do
260
+ assert_equal 100, Sidekiq.options[:concurrency]
261
+ assert_equal @tmp_lib_path, Sidekiq.options[:require]
262
+ assert_equal 'snoop', Sidekiq.options[:environment]
263
+ assert_equal @tmp_path, Sidekiq.options[:pidfile]
264
+ assert_equal 7, Sidekiq.options[:queues].count { |q| q == 'often' }
265
+ assert_equal 3, Sidekiq.options[:queues].count { |q| q == 'seldom' }
266
+ end
267
+ end
268
+
269
+ describe 'Sidekiq::CLI#parse_queues' do
270
+ describe 'when weight is present' do
271
+ it 'concatenates queues by factor of weight and sets strict to false' do
272
+ opts = { strict: true }
273
+ @cli.__send__ :parse_queues, opts, [['often', 7], ['repeatedly', 3]]
274
+ @cli.__send__ :parse_queues, opts, [['once']]
275
+ assert_equal (%w[often] * 7 + %w[repeatedly] * 3 + %w[once]), opts[:queues]
276
+ assert !opts[:strict]
277
+ end
278
+ end
279
+
280
+ describe 'when weight is not present' do
281
+ it 'returns queues and sets strict' do
282
+ opts = { strict: true }
283
+ @cli.__send__ :parse_queues, opts, [['once'], ['one_time']]
284
+ @cli.__send__ :parse_queues, opts, [['einmal']]
285
+ assert_equal %w[once one_time einmal], opts[:queues]
286
+ assert opts[:strict]
287
+ end
288
+ end
289
+ end
290
+
291
+ describe 'Sidekiq::CLI#parse_queue' do
292
+ describe 'when weight is present' do
293
+ it 'concatenates queue to opts[:queues] weight number of times and sets strict to false' do
294
+ opts = { strict: true }
295
+ @cli.__send__ :parse_queue, opts, 'often', 7
296
+ assert_equal %w[often] * 7, opts[:queues]
297
+ assert !opts[:strict]
298
+ end
299
+ end
300
+
301
+ describe 'when weight is not present' do
302
+ it 'concatenates queue to opts[:queues] once and leaves strict true' do
303
+ opts = { strict: true }
304
+ @cli.__send__ :parse_queue, opts, 'once', nil
305
+ assert_equal %w[once], opts[:queues]
306
+ assert opts[:strict]
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+ describe 'misc' do
313
+ before do
314
+ @cli = Sidekiq::CLI.new
315
+ end
316
+
317
+ it 'handles interrupts' do
318
+ assert_raises Interrupt do
319
+ @cli.handle_signal('INT')
320
+ end
321
+ assert_raises Interrupt do
322
+ @cli.handle_signal('TERM')
323
+ end
324
+ end
325
+
326
+ describe 'handles USR1 and USR2' do
327
+ before do
328
+ @tmp_log_path = '/tmp/sidekiq.log'
329
+ @cli.parse(['sidekiq', '-L', @tmp_log_path, '-r', './test/fake_env.rb'])
330
+ end
331
+
332
+ after do
333
+ File.unlink @tmp_log_path if File.exists? @tmp_log_path
334
+ end
335
+
336
+ it 'shuts down the worker' do
337
+ count = 0
338
+ Sidekiq.options[:lifecycle_events][:quiet] = [proc {
339
+ count += 1
340
+ }]
341
+ @cli.launcher = Sidekiq::Launcher.new(Sidekiq.options)
342
+ @cli.handle_signal('USR1')
343
+
344
+ assert_equal 1, count
345
+ end
346
+
347
+ it 'reopens logs' do
348
+ mock = MiniTest::Mock.new
349
+ # reopen_logs returns number of files reopened so mock that
350
+ mock.expect(:call, 1)
351
+
352
+ Sidekiq::Logging.stub(:reopen_logs, mock) do
353
+ @cli.handle_signal('USR2')
354
+ end
355
+ mock.verify
356
+ end
357
+ end
358
+
359
+ describe 'handles TTIN' do
360
+ before do
361
+ @tmp_log_path = '/tmp/sidekiq.log'
362
+ @cli.parse(['sidekiq', '-L', @tmp_log_path, '-r', './test/fake_env.rb'])
363
+ @mock_thread = MiniTest::Mock.new
364
+ @mock_thread.expect(:[], 'interrupt_test', ['label'])
365
+ end
366
+
367
+ after do
368
+ File.unlink @tmp_log_path if File.exists? @tmp_log_path
369
+ end
370
+
371
+ describe 'with backtrace' do
372
+ it 'logs backtrace' do
373
+ 2.times { @mock_thread.expect(:backtrace, ['something went wrong']) }
374
+
375
+ Thread.stub(:list, [@mock_thread]) do
376
+ @cli.handle_signal('TTIN')
377
+ assert_match(/something went wrong/, File.read(@tmp_log_path), "didn't include the log message")
378
+ end
379
+ end
380
+ end
381
+
382
+ describe 'without backtrace' do
383
+ it 'logs no backtrace available' do
384
+ @mock_thread.expect(:backtrace, nil)
385
+
386
+ Thread.stub(:list, [@mock_thread]) do
387
+ @cli.handle_signal('TTIN')
388
+ assert_match(/no backtrace available/, File.read(@tmp_log_path), "didn't include the log message")
389
+ end
390
+ end
391
+ end
392
+ end
393
+
394
+
395
+ it 'can fire events' do
396
+ count = 0
397
+ Sidekiq.options[:lifecycle_events][:startup] = [proc {
398
+ count += 1
399
+ }]
400
+ cli = Sidekiq::CLI.new
401
+ cli.fire_event(:startup)
402
+ assert_equal 1, count
403
+ end
404
+ end
405
+
406
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'helper'
3
+
4
+ class TestClient < Sidekiq::Test
5
+ describe 'errors' do
6
+ it 'raises ArgumentError with invalid params' do
7
+ assert_raises ArgumentError do
8
+ Sidekiq::Client.push('foo', 1)
9
+ end
10
+
11
+ assert_raises ArgumentError do
12
+ Sidekiq::Client.push('foo', :class => 'Foo', :noargs => [1, 2])
13
+ end
14
+
15
+ assert_raises ArgumentError do
16
+ Sidekiq::Client.push('queue' => 'foo', 'class' => MyWorker, 'noargs' => [1, 2])
17
+ end
18
+
19
+ assert_raises ArgumentError do
20
+ Sidekiq::Client.push('queue' => 'foo', 'class' => 42, 'args' => [1, 2])
21
+ end
22
+
23
+ assert_raises ArgumentError do
24
+ Sidekiq::Client.push('queue' => 'foo', 'class' => MyWorker, 'args' => 1)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe 'as instance' do
30
+ it 'can push' do
31
+ client = Sidekiq::Client.new
32
+ jid = client.push('class' => 'Blah', 'args' => [1,2,3])
33
+ assert_equal 24, jid.size
34
+ end
35
+
36
+ it 'allows middleware to stop bulk jobs' do
37
+ mware = Class.new do
38
+ def call(worker_klass,msg,q,r)
39
+ msg['args'][0] == 1 ? yield : false
40
+ end
41
+ end
42
+ client = Sidekiq::Client.new
43
+ client.middleware do |chain|
44
+ chain.add mware
45
+ end
46
+ q = Sidekiq::Queue.new
47
+ q.clear
48
+ result = client.push_bulk('class' => 'Blah', 'args' => [[1],[2],[3]])
49
+ assert_equal 1, result.size
50
+ assert_equal 1, q.size
51
+ end
52
+
53
+ it 'allows local middleware modification' do
54
+ $called = false
55
+ mware = Class.new { def call(worker_klass,msg,q,r); $called = true; msg;end }
56
+ client = Sidekiq::Client.new
57
+ client.middleware do |chain|
58
+ chain.add mware
59
+ end
60
+ client.push('class' => 'Blah', 'args' => [1,2,3])
61
+
62
+ assert $called
63
+ assert client.middleware.exists?(mware)
64
+ refute Sidekiq.client_middleware.exists?(mware)
65
+ end
66
+ end
67
+
68
+ describe 'client' do
69
+ it 'pushes messages to redis' do
70
+ q = Sidekiq::Queue.new('foo')
71
+ pre = q.size
72
+ jid = Sidekiq::Client.push('queue' => 'foo', 'class' => MyWorker, 'args' => [1, 2])
73
+ assert jid
74
+ assert_equal 24, jid.size
75
+ assert_equal pre + 1, q.size
76
+ end
77
+
78
+ it 'pushes messages to redis using a String class' do
79
+ q = Sidekiq::Queue.new('foo')
80
+ pre = q.size
81
+ jid = Sidekiq::Client.push('queue' => 'foo', 'class' => 'MyWorker', 'args' => [1, 2])
82
+ assert jid
83
+ assert_equal 24, jid.size
84
+ assert_equal pre + 1, q.size
85
+ end
86
+
87
+ class MyWorker
88
+ include Sidekiq::Worker
89
+ end
90
+
91
+ class QueuedWorker
92
+ include Sidekiq::Worker
93
+ sidekiq_options :queue => :flimflam
94
+ end
95
+
96
+ it 'enqueues' do
97
+ Sidekiq.redis {|c| c.flushdb }
98
+ assert_equal Sidekiq.default_worker_options, MyWorker.get_sidekiq_options
99
+ assert MyWorker.perform_async(1, 2)
100
+ assert Sidekiq::Client.enqueue(MyWorker, 1, 2)
101
+ assert Sidekiq::Client.enqueue_to(:custom_queue, MyWorker, 1, 2)
102
+ assert_equal 1, Sidekiq::Queue.new('custom_queue').size
103
+ assert Sidekiq::Client.enqueue_to_in(:custom_queue, 3.minutes, MyWorker, 1, 2)
104
+ assert Sidekiq::Client.enqueue_to_in(:custom_queue, -3.minutes, MyWorker, 1, 2)
105
+ assert_equal 2, Sidekiq::Queue.new('custom_queue').size
106
+ assert Sidekiq::Client.enqueue_in(3.minutes, MyWorker, 1, 2)
107
+ assert QueuedWorker.perform_async(1, 2)
108
+ assert_equal 1, Sidekiq::Queue.new('flimflam').size
109
+ end
110
+ end
111
+
112
+ describe 'bulk' do
113
+ after do
114
+ Sidekiq::Queue.new.clear
115
+ end
116
+ it 'can push a large set of jobs at once' do
117
+ jids = Sidekiq::Client.push_bulk('class' => QueuedWorker, 'args' => (1..1_000).to_a.map { |x| Array(x) })
118
+ assert_equal 1_000, jids.size
119
+ end
120
+ it 'can push a large set of jobs at once using a String class' do
121
+ jids = Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..1_000).to_a.map { |x| Array(x) })
122
+ assert_equal 1_000, jids.size
123
+ end
124
+ it 'returns the jids for the jobs' do
125
+ Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..2).to_a.map { |x| Array(x) }).each do |jid|
126
+ assert_match(/[0-9a-f]{12}/, jid)
127
+ end
128
+ end
129
+ end
130
+
131
+ class BaseWorker
132
+ include Sidekiq::Worker
133
+ sidekiq_options 'retry' => 'base'
134
+ end
135
+ class AWorker < BaseWorker
136
+ end
137
+ class BWorker < BaseWorker
138
+ sidekiq_options 'retry' => 'b'
139
+ end
140
+ class CWorker < BaseWorker
141
+ sidekiq_options 'retry' => 2
142
+ end
143
+
144
+ describe 'client middleware' do
145
+ class Stopper
146
+ def call(worker_class, job, queue, r)
147
+ raise ArgumentError unless r
148
+ yield if job['args'].first.odd?
149
+ end
150
+ end
151
+
152
+ it 'can stop some of the jobs from pushing' do
153
+ client = Sidekiq::Client.new
154
+ client.middleware do |chain|
155
+ chain.add Stopper
156
+ end
157
+
158
+ assert_equal nil, client.push('class' => MyWorker, 'args' => [0])
159
+ assert_match(/[0-9a-f]{12}/, client.push('class' => MyWorker, 'args' => [1]))
160
+ client.push_bulk('class' => MyWorker, 'args' => [[0], [1]]).each do |jid|
161
+ assert_match(/[0-9a-f]{12}/, jid)
162
+ end
163
+ end
164
+ end
165
+
166
+ describe 'inheritance' do
167
+ it 'inherits sidekiq options' do
168
+ assert_equal 'base', AWorker.get_sidekiq_options['retry']
169
+ assert_equal 'b', BWorker.get_sidekiq_options['retry']
170
+ end
171
+ end
172
+
173
+ describe 'sharding' do
174
+ class DWorker < BaseWorker
175
+ end
176
+
177
+ it 'allows sidekiq_options to point to different Redi' do
178
+ conn = MiniTest::Mock.new
179
+ conn.expect(:multi, [0, 1])
180
+ DWorker.sidekiq_options('pool' => ConnectionPool.new(size: 1) { conn })
181
+ DWorker.perform_async(1,2,3)
182
+ conn.verify
183
+ end
184
+
185
+ it 'allows #via to point to same Redi' do
186
+ conn = MiniTest::Mock.new
187
+ conn.expect(:multi, [0, 1])
188
+ sharded_pool = ConnectionPool.new(size: 1) { conn }
189
+ Sidekiq::Client.via(sharded_pool) do
190
+ Sidekiq::Client.via(sharded_pool) do
191
+ CWorker.perform_async(1,2,3)
192
+ end
193
+ end
194
+ conn.verify
195
+ end
196
+
197
+ it 'allows #via to point to different Redi' do
198
+ conn = MiniTest::Mock.new
199
+ conn.expect(:multi, [0, 1])
200
+ default = Sidekiq::Client.new.redis_pool
201
+ sharded_pool = ConnectionPool.new(size: 1) { conn }
202
+ Sidekiq::Client.via(sharded_pool) do
203
+ CWorker.perform_async(1,2,3)
204
+ assert_equal sharded_pool, Sidekiq::Client.new.redis_pool
205
+ assert_raises RuntimeError do
206
+ Sidekiq::Client.via(default) do
207
+ # nothing
208
+ end
209
+ end
210
+ end
211
+ assert_equal default, Sidekiq::Client.new.redis_pool
212
+ conn.verify
213
+ end
214
+
215
+ it 'allows Resque helpers to point to different Redi' do
216
+ conn = MiniTest::Mock.new
217
+ conn.expect(:multi, []) { |*args, &block| block.call }
218
+ conn.expect(:zadd, 1, [String, Array])
219
+ DWorker.sidekiq_options('pool' => ConnectionPool.new(size: 1) { conn })
220
+ Sidekiq::Client.enqueue_in(10, DWorker, 3)
221
+ conn.verify
222
+ end
223
+ end
224
+
225
+ describe 'Sidekiq::Worker#set' do
226
+ class SetWorker
227
+ include Sidekiq::Worker
228
+ sidekiq_options :queue => :foo, 'retry' => 12
229
+ end
230
+
231
+ def setup
232
+ Sidekiq.redis {|c| c.flushdb }
233
+ end
234
+
235
+ it 'allows option overrides' do
236
+ q = Sidekiq::Queue.new('bar')
237
+ assert_equal 0, q.size
238
+ assert SetWorker.set(queue: :bar).perform_async(1)
239
+ job = q.first
240
+ assert_equal 'bar', job['queue']
241
+ assert_equal 12, job['retry']
242
+ end
243
+
244
+ it 'handles symbols and strings' do
245
+ q = Sidekiq::Queue.new('bar')
246
+ assert_equal 0, q.size
247
+ assert SetWorker.set('queue' => 'bar', :retry => 11).perform_async(1)
248
+ job = q.first
249
+ assert_equal 'bar', job['queue']
250
+ assert_equal 11, job['retry']
251
+
252
+ q.clear
253
+ assert SetWorker.perform_async(1)
254
+ assert_equal 0, q.size
255
+
256
+ q = Sidekiq::Queue.new('foo')
257
+ job = q.first
258
+ assert_equal 'foo', job['queue']
259
+ assert_equal 12, job['retry']
260
+ end
261
+ end
262
+ end