sr-sidekiq 4.1.6

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 (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