roundhouse-x 0.1.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 (168) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +16 -0
  4. data/3.0-Upgrade.md +70 -0
  5. data/Changes.md +1127 -0
  6. data/Gemfile +27 -0
  7. data/LICENSE +7 -0
  8. data/README.md +52 -0
  9. data/Rakefile +9 -0
  10. data/bin/roundhouse +19 -0
  11. data/bin/roundhousectl +93 -0
  12. data/lib/generators/roundhouse/templates/worker.rb.erb +9 -0
  13. data/lib/generators/roundhouse/templates/worker_spec.rb.erb +6 -0
  14. data/lib/generators/roundhouse/templates/worker_test.rb.erb +8 -0
  15. data/lib/generators/roundhouse/worker_generator.rb +49 -0
  16. data/lib/roundhouse/actor.rb +39 -0
  17. data/lib/roundhouse/api.rb +859 -0
  18. data/lib/roundhouse/cli.rb +396 -0
  19. data/lib/roundhouse/client.rb +210 -0
  20. data/lib/roundhouse/core_ext.rb +105 -0
  21. data/lib/roundhouse/exception_handler.rb +30 -0
  22. data/lib/roundhouse/fetch.rb +154 -0
  23. data/lib/roundhouse/launcher.rb +98 -0
  24. data/lib/roundhouse/logging.rb +104 -0
  25. data/lib/roundhouse/manager.rb +236 -0
  26. data/lib/roundhouse/middleware/chain.rb +149 -0
  27. data/lib/roundhouse/middleware/i18n.rb +41 -0
  28. data/lib/roundhouse/middleware/server/active_record.rb +13 -0
  29. data/lib/roundhouse/middleware/server/logging.rb +40 -0
  30. data/lib/roundhouse/middleware/server/retry_jobs.rb +206 -0
  31. data/lib/roundhouse/monitor.rb +124 -0
  32. data/lib/roundhouse/paginator.rb +42 -0
  33. data/lib/roundhouse/processor.rb +159 -0
  34. data/lib/roundhouse/rails.rb +24 -0
  35. data/lib/roundhouse/redis_connection.rb +77 -0
  36. data/lib/roundhouse/scheduled.rb +115 -0
  37. data/lib/roundhouse/testing/inline.rb +28 -0
  38. data/lib/roundhouse/testing.rb +193 -0
  39. data/lib/roundhouse/util.rb +68 -0
  40. data/lib/roundhouse/version.rb +3 -0
  41. data/lib/roundhouse/web.rb +264 -0
  42. data/lib/roundhouse/web_helpers.rb +249 -0
  43. data/lib/roundhouse/worker.rb +90 -0
  44. data/lib/roundhouse.rb +177 -0
  45. data/roundhouse.gemspec +27 -0
  46. data/test/config.yml +9 -0
  47. data/test/env_based_config.yml +11 -0
  48. data/test/fake_env.rb +0 -0
  49. data/test/fixtures/en.yml +2 -0
  50. data/test/helper.rb +49 -0
  51. data/test/test_api.rb +521 -0
  52. data/test/test_cli.rb +389 -0
  53. data/test/test_client.rb +294 -0
  54. data/test/test_exception_handler.rb +55 -0
  55. data/test/test_fetch.rb +206 -0
  56. data/test/test_logging.rb +34 -0
  57. data/test/test_manager.rb +169 -0
  58. data/test/test_middleware.rb +160 -0
  59. data/test/test_monitor.rb +258 -0
  60. data/test/test_processor.rb +176 -0
  61. data/test/test_rails.rb +23 -0
  62. data/test/test_redis_connection.rb +127 -0
  63. data/test/test_retry.rb +390 -0
  64. data/test/test_roundhouse.rb +87 -0
  65. data/test/test_scheduled.rb +120 -0
  66. data/test/test_scheduling.rb +75 -0
  67. data/test/test_testing.rb +78 -0
  68. data/test/test_testing_fake.rb +240 -0
  69. data/test/test_testing_inline.rb +65 -0
  70. data/test/test_util.rb +18 -0
  71. data/test/test_web.rb +605 -0
  72. data/test/test_web_helpers.rb +52 -0
  73. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  74. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  75. data/web/assets/images/logo.png +0 -0
  76. data/web/assets/images/status/active.png +0 -0
  77. data/web/assets/images/status/idle.png +0 -0
  78. data/web/assets/images/status-sd8051fd480.png +0 -0
  79. data/web/assets/javascripts/application.js +83 -0
  80. data/web/assets/javascripts/dashboard.js +300 -0
  81. data/web/assets/javascripts/locales/README.md +27 -0
  82. data/web/assets/javascripts/locales/jquery.timeago.ar.js +96 -0
  83. data/web/assets/javascripts/locales/jquery.timeago.bg.js +18 -0
  84. data/web/assets/javascripts/locales/jquery.timeago.bs.js +49 -0
  85. data/web/assets/javascripts/locales/jquery.timeago.ca.js +18 -0
  86. data/web/assets/javascripts/locales/jquery.timeago.cs.js +18 -0
  87. data/web/assets/javascripts/locales/jquery.timeago.cy.js +20 -0
  88. data/web/assets/javascripts/locales/jquery.timeago.da.js +18 -0
  89. data/web/assets/javascripts/locales/jquery.timeago.de.js +18 -0
  90. data/web/assets/javascripts/locales/jquery.timeago.el.js +18 -0
  91. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +20 -0
  92. data/web/assets/javascripts/locales/jquery.timeago.en.js +20 -0
  93. data/web/assets/javascripts/locales/jquery.timeago.es.js +18 -0
  94. data/web/assets/javascripts/locales/jquery.timeago.et.js +18 -0
  95. data/web/assets/javascripts/locales/jquery.timeago.fa.js +22 -0
  96. data/web/assets/javascripts/locales/jquery.timeago.fi.js +28 -0
  97. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +16 -0
  98. data/web/assets/javascripts/locales/jquery.timeago.fr.js +17 -0
  99. data/web/assets/javascripts/locales/jquery.timeago.he.js +18 -0
  100. data/web/assets/javascripts/locales/jquery.timeago.hr.js +49 -0
  101. data/web/assets/javascripts/locales/jquery.timeago.hu.js +18 -0
  102. data/web/assets/javascripts/locales/jquery.timeago.hy.js +18 -0
  103. data/web/assets/javascripts/locales/jquery.timeago.id.js +18 -0
  104. data/web/assets/javascripts/locales/jquery.timeago.it.js +16 -0
  105. data/web/assets/javascripts/locales/jquery.timeago.ja.js +19 -0
  106. data/web/assets/javascripts/locales/jquery.timeago.ko.js +17 -0
  107. data/web/assets/javascripts/locales/jquery.timeago.lt.js +20 -0
  108. data/web/assets/javascripts/locales/jquery.timeago.mk.js +20 -0
  109. data/web/assets/javascripts/locales/jquery.timeago.nl.js +20 -0
  110. data/web/assets/javascripts/locales/jquery.timeago.no.js +18 -0
  111. data/web/assets/javascripts/locales/jquery.timeago.pl.js +31 -0
  112. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +16 -0
  113. data/web/assets/javascripts/locales/jquery.timeago.pt.js +16 -0
  114. data/web/assets/javascripts/locales/jquery.timeago.ro.js +18 -0
  115. data/web/assets/javascripts/locales/jquery.timeago.rs.js +49 -0
  116. data/web/assets/javascripts/locales/jquery.timeago.ru.js +34 -0
  117. data/web/assets/javascripts/locales/jquery.timeago.sk.js +18 -0
  118. data/web/assets/javascripts/locales/jquery.timeago.sl.js +44 -0
  119. data/web/assets/javascripts/locales/jquery.timeago.sv.js +18 -0
  120. data/web/assets/javascripts/locales/jquery.timeago.th.js +20 -0
  121. data/web/assets/javascripts/locales/jquery.timeago.tr.js +16 -0
  122. data/web/assets/javascripts/locales/jquery.timeago.uk.js +34 -0
  123. data/web/assets/javascripts/locales/jquery.timeago.uz.js +19 -0
  124. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +20 -0
  125. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +20 -0
  126. data/web/assets/stylesheets/application.css +746 -0
  127. data/web/assets/stylesheets/bootstrap.css +9 -0
  128. data/web/locales/cs.yml +68 -0
  129. data/web/locales/da.yml +68 -0
  130. data/web/locales/de.yml +69 -0
  131. data/web/locales/el.yml +68 -0
  132. data/web/locales/en.yml +77 -0
  133. data/web/locales/es.yml +69 -0
  134. data/web/locales/fr.yml +69 -0
  135. data/web/locales/hi.yml +75 -0
  136. data/web/locales/it.yml +69 -0
  137. data/web/locales/ja.yml +69 -0
  138. data/web/locales/ko.yml +68 -0
  139. data/web/locales/nl.yml +68 -0
  140. data/web/locales/no.yml +69 -0
  141. data/web/locales/pl.yml +59 -0
  142. data/web/locales/pt-br.yml +68 -0
  143. data/web/locales/pt.yml +67 -0
  144. data/web/locales/ru.yml +75 -0
  145. data/web/locales/sv.yml +68 -0
  146. data/web/locales/ta.yml +75 -0
  147. data/web/locales/zh-cn.yml +68 -0
  148. data/web/locales/zh-tw.yml +68 -0
  149. data/web/views/_footer.erb +22 -0
  150. data/web/views/_job_info.erb +84 -0
  151. data/web/views/_nav.erb +66 -0
  152. data/web/views/_paging.erb +23 -0
  153. data/web/views/_poll_js.erb +5 -0
  154. data/web/views/_poll_link.erb +7 -0
  155. data/web/views/_status.erb +4 -0
  156. data/web/views/_summary.erb +40 -0
  157. data/web/views/busy.erb +90 -0
  158. data/web/views/dashboard.erb +75 -0
  159. data/web/views/dead.erb +34 -0
  160. data/web/views/layout.erb +31 -0
  161. data/web/views/morgue.erb +71 -0
  162. data/web/views/queue.erb +45 -0
  163. data/web/views/queues.erb +27 -0
  164. data/web/views/retries.erb +74 -0
  165. data/web/views/retry.erb +34 -0
  166. data/web/views/scheduled.erb +54 -0
  167. data/web/views/scheduled_job_info.erb +8 -0
  168. metadata +404 -0
@@ -0,0 +1,78 @@
1
+ require_relative 'helper'
2
+ require 'roundhouse'
3
+ require 'roundhouse/worker'
4
+ require 'roundhouse/rails'
5
+
6
+ Roundhouse.hook_rails!
7
+
8
+ class TestTesting < Roundhouse::Test
9
+ describe 'roundhouse testing' do
10
+ describe 'require/load roundhouse/testing.rb' do
11
+ before do
12
+ require 'roundhouse/testing.rb'
13
+ end
14
+
15
+ after do
16
+ Roundhouse::Testing.disable!
17
+ end
18
+
19
+ it 'enables fake testing' do
20
+ Roundhouse::Testing.fake!
21
+ assert_equal true, Roundhouse::Testing.enabled?
22
+ assert_equal true, Roundhouse::Testing.fake?
23
+ end
24
+
25
+ it 'enables fake testing in a block' do
26
+ Roundhouse::Testing.disable!
27
+ assert_equal true, Roundhouse::Testing.disabled?
28
+
29
+ Roundhouse::Testing.fake! do
30
+ assert_equal true, Roundhouse::Testing.enabled?
31
+ assert_equal true, Roundhouse::Testing.fake?
32
+ end
33
+
34
+ assert_equal false, Roundhouse::Testing.enabled?
35
+ assert_equal false, Roundhouse::Testing.fake?
36
+ end
37
+
38
+ it 'disables testing in a block' do
39
+ Roundhouse::Testing.fake!
40
+
41
+ Roundhouse::Testing.disable! do
42
+ assert_equal true, Roundhouse::Testing.disabled?
43
+ end
44
+
45
+ assert_equal true, Roundhouse::Testing.enabled?
46
+ end
47
+ end
48
+
49
+ describe 'require/load roundhouse/testing/inline.rb' do
50
+ before do
51
+ require 'roundhouse/testing/inline.rb'
52
+ end
53
+
54
+ after do
55
+ Roundhouse::Testing.disable!
56
+ end
57
+
58
+ it 'enables inline testing' do
59
+ Roundhouse::Testing.inline!
60
+ assert_equal true, Roundhouse::Testing.enabled?
61
+ assert_equal true, Roundhouse::Testing.inline?
62
+ end
63
+
64
+ it 'enables inline testing in a block' do
65
+ Roundhouse::Testing.disable!
66
+ assert_equal true, Roundhouse::Testing.disabled?
67
+
68
+ Roundhouse::Testing.inline! do
69
+ assert_equal true, Roundhouse::Testing.enabled?
70
+ assert_equal true, Roundhouse::Testing.inline?
71
+ end
72
+
73
+ assert_equal false, Roundhouse::Testing.enabled?
74
+ assert_equal false, Roundhouse::Testing.inline?
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,240 @@
1
+ require_relative 'helper'
2
+ require 'roundhouse'
3
+ require 'roundhouse/worker'
4
+ require 'roundhouse/rails'
5
+
6
+ require 'active_support/core_ext/numeric/time'
7
+
8
+ Roundhouse.hook_rails!
9
+
10
+ class TestTesting < Roundhouse::Test
11
+ describe 'roundhouse testing' do
12
+ class PerformError < RuntimeError; end
13
+
14
+ class DirectWorker
15
+ include Roundhouse::Worker
16
+ def perform(a, b)
17
+ a + b
18
+ end
19
+ end
20
+
21
+ class EnqueuedWorker
22
+ include Roundhouse::Worker
23
+ def perform(a, b)
24
+ a + b
25
+ end
26
+ end
27
+
28
+ class StoredWorker
29
+ include Roundhouse::Worker
30
+ def perform(error)
31
+ raise PerformError if error
32
+ end
33
+ end
34
+
35
+ before do
36
+ require 'roundhouse/testing.rb'
37
+ Roundhouse::Testing.fake!
38
+ EnqueuedWorker.jobs.clear
39
+ DirectWorker.jobs.clear
40
+ end
41
+
42
+ after do
43
+ Roundhouse::Testing.disable!
44
+ end
45
+
46
+ it 'stubs the async call' do
47
+ assert_equal 0, DirectWorker.jobs.size
48
+ assert DirectWorker.perform_async(100, 1, 2)
49
+ assert_equal 1, DirectWorker.jobs.size
50
+ assert DirectWorker.perform_in(100, 10, 1, 2)
51
+ assert_equal 2, DirectWorker.jobs.size
52
+ assert DirectWorker.perform_at(100, 10, 1, 2)
53
+ assert_equal 3, DirectWorker.jobs.size
54
+ assert_in_delta 10.seconds.from_now.to_f, DirectWorker.jobs.last['at'], 0.01
55
+ end
56
+
57
+ it 'stubs the enqueue call' do
58
+ assert_equal 0, EnqueuedWorker.jobs.size
59
+ assert Roundhouse::Client.enqueue_to(100, EnqueuedWorker, 1, 2)
60
+ assert_equal 1, EnqueuedWorker.jobs.size
61
+ end
62
+
63
+ it 'stubs the enqueue_to call' do
64
+ assert_equal 0, EnqueuedWorker.jobs.size
65
+ assert Roundhouse::Client.enqueue_to(1000, EnqueuedWorker, 1, 2)
66
+ assert_equal 1, EnqueuedWorker.jobs.size
67
+ end
68
+
69
+ it 'executes all stored jobs' do
70
+ assert StoredWorker.perform_async(100, false)
71
+ assert StoredWorker.perform_async(100, true)
72
+
73
+ assert_equal 2, StoredWorker.jobs.size
74
+ assert_raises PerformError do
75
+ StoredWorker.drain
76
+ end
77
+ assert_equal 0, StoredWorker.jobs.size
78
+
79
+ end
80
+
81
+ class SpecificJidWorker
82
+ include Roundhouse::Worker
83
+ class_attribute :count
84
+ self.count = 0
85
+ def perform(worker_jid)
86
+ return unless worker_jid == self.jid
87
+ self.class.count += 1
88
+ end
89
+ end
90
+
91
+ it 'execute only jobs with assigned JID' do
92
+ 4.times do |i|
93
+ jid = SpecificJidWorker.perform_async(100, nil)
94
+ if i % 2 == 0
95
+ SpecificJidWorker.jobs[-1]["args"] = ["wrong_jid"]
96
+ else
97
+ SpecificJidWorker.jobs[-1]["args"] = [jid]
98
+ end
99
+ end
100
+
101
+ SpecificJidWorker.perform_one
102
+ assert_equal 0, SpecificJidWorker.count
103
+
104
+ SpecificJidWorker.perform_one
105
+ assert_equal 1, SpecificJidWorker.count
106
+
107
+ SpecificJidWorker.drain
108
+ assert_equal 2, SpecificJidWorker.count
109
+ end
110
+
111
+ it 'round trip serializes the job arguments' do
112
+ assert StoredWorker.perform_async(100, :mike)
113
+ job = StoredWorker.jobs.first
114
+ assert_equal "mike", job['args'].first
115
+ StoredWorker.clear
116
+ end
117
+
118
+ it 'perform_one runs only one job' do
119
+ DirectWorker.perform_async(100, 1, 2)
120
+ DirectWorker.perform_async(100, 3, 4)
121
+ assert_equal 2, DirectWorker.jobs.size
122
+
123
+ DirectWorker.perform_one
124
+ assert_equal 1, DirectWorker.jobs.size
125
+
126
+ DirectWorker.clear
127
+ end
128
+
129
+ it 'perform_one raise error upon empty queue' do
130
+ DirectWorker.clear
131
+ assert_raises Roundhouse::EmptyQueueError do
132
+ DirectWorker.perform_one
133
+ end
134
+ end
135
+
136
+ class FirstWorker
137
+ include Roundhouse::Worker
138
+ class_attribute :count
139
+ self.count = 0
140
+ def perform
141
+ self.class.count += 1
142
+ end
143
+ end
144
+
145
+ class SecondWorker
146
+ include Roundhouse::Worker
147
+ class_attribute :count
148
+ self.count = 0
149
+ def perform
150
+ self.class.count += 1
151
+ end
152
+ end
153
+
154
+ class ThirdWorker
155
+ include Roundhouse::Worker
156
+ class_attribute :count
157
+ def perform
158
+ FirstWorker.perform_async(100)
159
+ SecondWorker.perform_async(100)
160
+ end
161
+ end
162
+
163
+ it 'clears jobs across all workers' do
164
+ Roundhouse::Worker.jobs.clear
165
+ FirstWorker.count = 0
166
+ SecondWorker.count = 0
167
+
168
+ assert_equal 0, FirstWorker.jobs.size
169
+ assert_equal 0, SecondWorker.jobs.size
170
+
171
+ FirstWorker.perform_async(100)
172
+ SecondWorker.perform_async(100)
173
+
174
+ assert_equal 1, FirstWorker.jobs.size
175
+ assert_equal 1, SecondWorker.jobs.size
176
+
177
+ Roundhouse::Worker.clear_all
178
+
179
+ assert_equal 0, FirstWorker.jobs.size
180
+ assert_equal 0, SecondWorker.jobs.size
181
+
182
+ assert_equal 0, FirstWorker.count
183
+ assert_equal 0, SecondWorker.count
184
+ end
185
+
186
+ it 'drains jobs across all workers' do
187
+ Roundhouse::Worker.jobs.clear
188
+ FirstWorker.count = 0
189
+ SecondWorker.count = 0
190
+
191
+ assert_equal 0, FirstWorker.jobs.size
192
+ assert_equal 0, SecondWorker.jobs.size
193
+
194
+ assert_equal 0, FirstWorker.count
195
+ assert_equal 0, SecondWorker.count
196
+
197
+ FirstWorker.perform_async(100)
198
+ SecondWorker.perform_async(100)
199
+
200
+ assert_equal 1, FirstWorker.jobs.size
201
+ assert_equal 1, SecondWorker.jobs.size
202
+
203
+ Roundhouse::Worker.drain_all
204
+
205
+ assert_equal 0, FirstWorker.jobs.size
206
+ assert_equal 0, SecondWorker.jobs.size
207
+
208
+ assert_equal 1, FirstWorker.count
209
+ assert_equal 1, SecondWorker.count
210
+ end
211
+
212
+ it 'drains jobs across all workers even when workers create new jobs' do
213
+ Roundhouse::Worker.jobs.clear
214
+ FirstWorker.count = 0
215
+ SecondWorker.count = 0
216
+
217
+ assert_equal 0, ThirdWorker.jobs.size
218
+
219
+ assert_equal 0, FirstWorker.count
220
+ assert_equal 0, SecondWorker.count
221
+
222
+ ThirdWorker.perform_async(100)
223
+
224
+ assert_equal 1, ThirdWorker.jobs.size
225
+
226
+ Roundhouse::Worker.drain_all
227
+
228
+ assert_equal 0, ThirdWorker.jobs.size
229
+
230
+ assert_equal 1, FirstWorker.count
231
+ assert_equal 1, SecondWorker.count
232
+ end
233
+
234
+ it 'can execute a job' do
235
+ worker = Minitest::Mock.new
236
+ worker.expect(:perform, nil, [1, 2, 3])
237
+ DirectWorker.execute_job(worker, [1, 2, 3])
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'helper'
2
+ require 'roundhouse'
3
+ require 'roundhouse/worker'
4
+ require 'roundhouse/rails'
5
+
6
+ Roundhouse.hook_rails!
7
+
8
+ class TestInline < Roundhouse::Test
9
+ describe 'roundhouse inline testing' do
10
+ class InlineError < RuntimeError; end
11
+ class ParameterIsNotString < RuntimeError; end
12
+
13
+ class InlineWorker
14
+ include Roundhouse::Worker
15
+ def perform(pass)
16
+ raise ArgumentError, "no jid" unless jid
17
+ raise InlineError unless pass
18
+ end
19
+ end
20
+
21
+ class InlineWorkerWithTimeParam
22
+ include Roundhouse::Worker
23
+ def perform(time)
24
+ raise ParameterIsNotString unless time.is_a?(String) || time.is_a?(Numeric)
25
+ end
26
+ end
27
+
28
+ before do
29
+ require 'roundhouse/testing/inline.rb'
30
+ Roundhouse::Testing.inline!
31
+ end
32
+
33
+ after do
34
+ Roundhouse::Testing.disable!
35
+ end
36
+
37
+ it 'stubs the async call when in testing mode' do
38
+ assert InlineWorker.perform_async(100, true)
39
+
40
+ assert_raises InlineError do
41
+ InlineWorker.perform_async(100, false)
42
+ end
43
+ end
44
+
45
+ it 'stubs the enqueue call when in testing mode' do
46
+ assert Roundhouse::Client.enqueue_to(100, InlineWorker, true)
47
+
48
+ assert_raises InlineError do
49
+ Roundhouse::Client.enqueue_to(100, InlineWorker, false)
50
+ end
51
+ end
52
+
53
+ it 'stubs the push_bulk call when in testing mode' do
54
+ assert Roundhouse::Client.push_bulk({'queue_id' => 100, 'class' => InlineWorker, 'args' => [[true], [true]]})
55
+
56
+ assert_raises InlineError do
57
+ Roundhouse::Client.push_bulk({'queue_id' => 100, 'class' => InlineWorker, 'args' => [[true], [false]]})
58
+ end
59
+ end
60
+
61
+ it 'should relay parameters through json' do
62
+ assert Roundhouse::Client.enqueue_to(100, InlineWorkerWithTimeParam, Time.now)
63
+ end
64
+ end
65
+ end
data/test/test_util.rb ADDED
@@ -0,0 +1,18 @@
1
+ require_relative 'helper'
2
+ require 'roundhouse'
3
+ require 'roundhouse/web_helpers'
4
+
5
+ class TestUtil < Roundhouse::Test
6
+
7
+ class Helpers
8
+ include Roundhouse::Util
9
+ end
10
+
11
+ def test_hertz_donut
12
+ obj = Helpers.new
13
+ output = capture_logging(Logger::DEBUG) do
14
+ assert_equal false, obj.want_a_hertz_donut?
15
+ end
16
+ assert_includes output, "hz: 10"
17
+ end
18
+ end