tq 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,50 +1,18 @@
1
1
  require 'fileutils'
2
2
  require_relative './helper'
3
- require_relative '../lib/tq/app'
3
+ require_relative '../lib/tq'
4
4
 
5
5
  def setup_logger!(name)
6
6
  TestUtils.setup_logger(name)
7
7
  end
8
8
 
9
- def delete_credentials!
10
- FileUtils.rm_f(CREDENTIALS_FILE)
11
- end
12
-
13
- # for installed app auth
14
- CLIENT_SECRETS_FILE = File.expand_path('../config/secrets/test/client_secrets.json', File.dirname(__FILE__))
15
- CREDENTIALS_FILE = File.expand_path("../config/secrets/test/#{File.basename(__FILE__,'.rb')}-oauth2.json", File.dirname(__FILE__))
16
-
17
- # for service account auth
18
- SERVICE_ISSUER_FILE = File.expand_path('../config/secrets/test/issuer', File.dirname(__FILE__))
19
- SERVICE_P12_FILE = File.expand_path('../config/secrets/test/client.p12', File.dirname(__FILE__))
9
+ SERVICE_ACCOUNT_FILE = File.expand_path(
10
+ '../config/secrets/test/service_account.json',
11
+ File.dirname(__FILE__)
12
+ )
20
13
 
21
14
  describe TQ::App do
22
15
 
23
- describe "auth" do
24
-
25
- before do
26
- setup_logger!('auth')
27
- delete_credentials!
28
- end
29
-
30
- it "should authorize without cached credentials" do
31
- app = TQ::App.new('test_app/0.0.0', nil)
32
- app.auth! CLIENT_SECRETS_FILE
33
- assert true
34
- end
35
-
36
- # Note: browser window should only appear once for this test
37
- # Not sure if it's possible to assert this
38
- it "should authorize with cached credentials not existing and existing" do
39
- app = TQ::App.new('test_app/0.0.0', nil)
40
- app.auth! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
41
- assert File.exists?(CREDENTIALS_FILE)
42
- app.auth! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
43
- assert File.exists?(CREDENTIALS_FILE)
44
- end
45
-
46
- end
47
-
48
16
  describe "service auth" do
49
17
 
50
18
  before do
@@ -52,8 +20,8 @@ describe TQ::App do
52
20
  end
53
21
 
54
22
  it "should authorize service account" do
55
- app = TQ::App.new('test_app/0.0.0', nil)
56
- app.service_auth!(File.read(SERVICE_ISSUER_FILE).chomp, SERVICE_P12_FILE)
23
+ app = TQ::App.new(nil, nil, nil, nil)
24
+ app.service_account_client(File.read(SERVICE_ACCOUNT_FILE).chomp)
57
25
  assert true
58
26
  end
59
27
 
@@ -7,8 +7,7 @@
7
7
  require 'logger'
8
8
 
9
9
  require_relative './helper'
10
- require_relative '../lib/tq/app'
11
- require_relative '../lib/tq/queue'
10
+ require_relative '../lib/tq'
12
11
  require_relative '../lib/tq/logger'
13
12
 
14
13
  def setup_test_logger!
@@ -18,26 +17,44 @@ end
18
17
 
19
18
  class LoggerTests < Minitest::Spec
20
19
 
21
- # for installed app auth
22
- CLIENT_SECRETS_FILE = File.expand_path(
23
- '../config/secrets/test/client_secrets.json', File.dirname(__FILE__)
24
- )
25
- CREDENTIALS_FILE = File.expand_path(
26
- "../config/secrets/test/#{File.basename(__FILE__,'.rb')}-oauth2.json",
27
- File.dirname(__FILE__)
20
+ # for service account auth
21
+ SERVICE_ACCOUNT_FILE = File.expand_path(
22
+ '../config/secrets/test/service_account.json', File.dirname(__FILE__)
28
23
  )
29
24
 
30
25
  # task queue constants
31
- TASKQUEUE_PROJECT_ID = File.read(
26
+ PROJECT_ID = File.read(
32
27
  File.expand_path('../config/secrets/test/project_id', File.dirname(__FILE__))
33
28
  ).chomp
34
-
35
- TASKQUEUE_TEST_QUEUE = 'log'
29
+
30
+ LOCATION = 'us-central1'
31
+ TASKQUEUE_LEASE_SECS = 2
32
+ TEST_QUEUE = 'log'
36
33
 
37
34
  def test_logger
38
35
  @test_logger ||= TestUtils.current_logger
39
36
  end
40
37
 
38
+ def queue_helper
39
+ TestUtils::QueueHelper.new(
40
+ TQ::QueueSpec.new( PROJECT_ID, LOCATION, TEST_QUEUE ),
41
+ SERVICE_ACCOUNT_FILE
42
+ )
43
+ end
44
+
45
+ def clear_queue!
46
+ queue_helper.clear!
47
+ end
48
+
49
+ def queue_spec(max_tasks)
50
+ TQ::QueueSpec.new( PROJECT_ID, LOCATION, TEST_QUEUE,
51
+ max_tasks: max_tasks, lease_duration: "#{TASKQUEUE_LEASE_SECS}s")
52
+ end
53
+
54
+ def service_account_client
55
+ TQ::ServiceAccount.client(SERVICE_ACCOUNT_FILE)
56
+ end
57
+
41
58
  def assert_logged( exps, acts )
42
59
  errs = []
43
60
  unless (a = exps.length) == (b = acts.length)
@@ -86,26 +103,17 @@ class LoggerTests < Minitest::Spec
86
103
  end
87
104
  end
88
105
 
89
- def queue_helper(project,queue)
90
- TestUtils::QueueHelper.new(project,queue).auth_files(CLIENT_SECRETS_FILE, CREDENTIALS_FILE)
91
- end
92
-
93
- def clear_queue!(project,queue)
94
- queue_helper(project,queue).clear!
95
- end
96
-
97
106
  def verify_logged_messages_to_level!(expected_messages, minlevel)
98
- actual_messages = queue_helper(TASKQUEUE_PROJECT_ID, TASKQUEUE_TEST_QUEUE).all_payloads_and_tags!
99
- $stderr.puts actual_messages.inspect
107
+ actual_messages = queue_helper.messages!
100
108
 
101
109
  selected_messages = expected_messages.select { |msg| msg[:level] >= minlevel }
102
110
 
103
111
  assert_logged( selected_messages,
104
- actual_messages.map { |msg| msg[:payload] }
112
+ actual_messages.map { |m| JSON.load(m.payload) }
105
113
  )
106
114
 
107
115
  assert_logged_tags( selected_messages,
108
- actual_messages.map { |msg| msg[:tag] }
116
+ actual_messages.map { |m| m.tag }
109
117
  )
110
118
  end
111
119
 
@@ -114,11 +122,8 @@ class LoggerTests < Minitest::Spec
114
122
  # you should just eyeball it in the $stderr output.
115
123
 
116
124
  def setup
117
- clear_queue!(TASKQUEUE_PROJECT_ID, TASKQUEUE_TEST_QUEUE)
118
-
119
- app = TQ::App.new('test_app/0.0.0', nil)
120
- @queue = TQ::Queue.new( *app.auth!(CLIENT_SECRETS_FILE, CREDENTIALS_FILE) )
121
- .options({ 'project' => TASKQUEUE_PROJECT_ID, 'name' => TASKQUEUE_TEST_QUEUE })
125
+ clear_queue!
126
+ @queue = TQ::Queue.new( service_account_client, queue_spec(1) )
122
127
  end
123
128
 
124
129
  it 'default logger should log to queue at warn level' do
@@ -5,7 +5,7 @@
5
5
  # along with other secrets files (see below).
6
6
 
7
7
  require_relative './helper'
8
- require_relative '../lib/tq/app'
8
+ require_relative '../lib/tq'
9
9
 
10
10
  def setup_test_logger!
11
11
  TestUtils.setup_logger( File.basename(__FILE__,'.rb') )
@@ -13,50 +13,44 @@ end
13
13
 
14
14
  class AppRunTests < Minitest::Spec
15
15
 
16
- # for installed app auth
17
- CLIENT_SECRETS_FILE = File.expand_path(
18
- '../config/secrets/test/client_secrets.json', File.dirname(__FILE__)
19
- )
20
- CREDENTIALS_FILE = File.expand_path(
21
- "../config/secrets/test/#{File.basename(__FILE__,'.rb')}-oauth2.json",
22
- File.dirname(__FILE__)
23
- )
24
-
25
- # for service account auth -- not quite working
26
- SERVICE_ISSUER_FILE = File.expand_path(
27
- '../config/secrets/test/issuer', File.dirname(__FILE__)
28
- )
29
- SERVICE_P12_FILE = File.expand_path(
30
- '../config/secrets/test/client.p12', File.dirname(__FILE__)
16
+ # for service account auth
17
+ SERVICE_ACCOUNT_FILE = File.expand_path(
18
+ '../config/secrets/test/service_account.json', File.dirname(__FILE__)
31
19
  )
32
20
 
33
21
  # task queue constants
34
- TASKQUEUE_PROJECT_ID = File.read(
22
+ PROJECT_ID = File.read(
35
23
  File.expand_path('../config/secrets/test/project_id', File.dirname(__FILE__))
36
24
  ).chomp
25
+
26
+ LOCATION = 'us-central1'
37
27
 
38
28
  TASKQUEUE_LEASE_SECS = 2
39
29
 
40
30
 
41
- def queue_helper(project,queue)
42
- TestUtils::QueueHelper.new(project,queue).service_auth_files(SERVICE_ISSUER_FILE, SERVICE_P12_FILE)
43
- end
44
-
45
- def tasks_on_queue(project,queue)
46
- queue_helper(project,queue).list
31
+ def queue_helper(queue)
32
+ TestUtils::QueueHelper.new(
33
+ TQ::QueueSpec.new( PROJECT_ID, LOCATION, queue ),
34
+ SERVICE_ACCOUNT_FILE
35
+ )
47
36
  end
48
37
 
49
- def clear_queue!(project,queue)
50
- queue_helper(project,queue).clear!
38
+ def clear_queue!(queue)
39
+ queue_helper(queue).clear!
51
40
  end
52
41
 
53
- def push_tasks!(project,queue,tasks)
54
- q = queue_helper(project,queue)
42
+ def push_tasks!(queue,tasks)
43
+ q = queue_helper(queue)
55
44
  tasks.each do |task| q.push!(task) end
56
45
  end
57
46
 
58
- def service_run!(app)
59
- app.service_run! File.read(SERVICE_ISSUER_FILE).chomp, SERVICE_P12_FILE
47
+ def queue_spec(name, max_tasks)
48
+ TQ::QueueSpec.new(PROJECT_ID, LOCATION, name,
49
+ max_tasks: max_tasks, lease_duration: "#{TASKQUEUE_LEASE_SECS}s")
50
+ end
51
+
52
+ def run!(app)
53
+ app.call SERVICE_ACCOUNT_FILE
60
54
  end
61
55
 
62
56
 
@@ -64,18 +58,13 @@ class AppRunTests < Minitest::Spec
64
58
 
65
59
  before do
66
60
  sleep TASKQUEUE_LEASE_SECS + 1 # to wait for lease expiry from previous test
67
- clear_queue!(TASKQUEUE_PROJECT_ID,'test')
68
- clear_queue!(TASKQUEUE_PROJECT_ID,'log')
61
+ clear_queue!('test')
62
+ clear_queue!('log')
69
63
  end
70
64
 
71
65
  it "should setup clearing the queue" do
72
- cleared = clear_queue!(TASKQUEUE_PROJECT_ID,'test')
73
- assert_equal 0, n = cleared.length,
74
- "Expected no tasks on queue, #{n < 2 ? 'was' : 'were'} #{n}"
75
-
76
- # unfortunately, queue peeks are horribly inaccurate right now.
77
- # assert_equal 0, n = tasks_on_queue(TASKQUEUE_PROJECT_ID,'test').length,
78
- # "Expected no tasks on queue, #{n < 2 ? 'was' : 'were'} #{n}"
66
+ cleared = clear_queue!('test')
67
+ assert true
79
68
  end
80
69
 
81
70
  it "worker should receive input queue and :call with each task on the queue up to the specified number" do
@@ -87,7 +76,7 @@ class AppRunTests < Minitest::Spec
87
76
  { 'What is your name?' => 'Galahad', 'What is your quest?' => 'To seek the grail', 'What is your favorite color?' => ['blue','yellow'] },
88
77
  { 'What is your name?' => 'Arthur', 'What is your quest?' => 'To seek the holy grail', 'What is the air-speed velocity of an unladen swallow?' => 'African or European swallow?' }
89
78
  ]
90
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
79
+ push_tasks!('test', expected_tasks)
91
80
 
92
81
  # expectations
93
82
  mock_handler_class = MiniTest::Mock.new
@@ -114,11 +103,8 @@ class AppRunTests < Minitest::Spec
114
103
  end
115
104
 
116
105
  # execution
117
- app = TQ::App.new('test_app/0.0.0', mock_handler_class)
118
- .project(TASKQUEUE_PROJECT_ID)
119
- .stdin({ 'name' => 'test', 'num_tasks' => expected_calls, 'lease_secs' => TASKQUEUE_LEASE_SECS })
120
- # app.run! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
121
- service_run! app
106
+ app = TQ::App.new(mock_handler_class, queue_spec('test', expected_calls))
107
+ run! app
122
108
 
123
109
  # assertions
124
110
  assert_equal expected_calls, actual_calls,
@@ -129,13 +115,14 @@ class AppRunTests < Minitest::Spec
129
115
 
130
116
  end
131
117
 
118
+
132
119
  it 'should put task back on input queue after lease_secs, if not finished' do
133
120
 
134
121
  # setup
135
122
  expected_tasks = [
136
123
  { 'What is your name?' => 'Sir Lancelot', 'What is your quest?' => 'To seek the holy grail', 'What is your favorite color?' => 'blue' }
137
124
  ]
138
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
125
+ push_tasks!('test', expected_tasks)
139
126
 
140
127
  class DoNothingWorker
141
128
  def initialize(*args); end
@@ -143,25 +130,16 @@ class AppRunTests < Minitest::Spec
143
130
  end
144
131
 
145
132
  # execution
146
- app = TQ::App.new('test_app/0.0.0', DoNothingWorker)
147
- .project(TASKQUEUE_PROJECT_ID)
148
- .stdin({ 'name' => 'test', 'num_tasks' => 1, 'lease_secs' => TASKQUEUE_LEASE_SECS })
149
- # app.run! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
150
- service_run! app
133
+ app = TQ::App.new(DoNothingWorker, queue_spec('test', 1))
134
+ run! app
151
135
 
152
136
  sleep TASKQUEUE_LEASE_SECS + 1
153
- actual_tasks = clear_queue!(TASKQUEUE_PROJECT_ID,'test')
137
+ actual_tasks = clear_queue!('test')
154
138
 
155
- ## queue peeks are inaccurate right now...
156
- # actual_tasks = tasks_on_queue(TASKQUEUE_PROJECT_ID,'test')
157
-
158
- ## assertion
139
+ # assertion
159
140
  assert_equal a = expected_tasks.length, b = actual_tasks.length,
160
141
  "Expected #{a} #{a == 1 ? 'task' : 'tasks'} on queue, #{b < 2 ? 'was' : 'were'} #{b}"
161
142
 
162
- assert (n = actual_tasks.first['retry_count']) > 0,
163
- "Expected >0 lease retry count, #{n < 2 ? 'was' : 'were'} #{n}"
164
-
165
143
  end
166
144
 
167
145
  it 'should be able to push to queue from within worker' do
@@ -170,7 +148,7 @@ class AppRunTests < Minitest::Spec
170
148
  expected_tasks = [
171
149
  { 'What is your name?' => 'Sir Lancelot', 'What is your quest?' => 'To seek the holy grail', 'What is your favorite color?' => 'blue' }
172
150
  ]
173
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
151
+ push_tasks!('test', expected_tasks)
174
152
 
175
153
  class RelayWorker
176
154
  def initialize(*args)
@@ -184,16 +162,12 @@ class AppRunTests < Minitest::Spec
184
162
  end
185
163
 
186
164
  # execution
187
- app = TQ::App.new('test_app/0.0.0', RelayWorker)
188
- .project(TASKQUEUE_PROJECT_ID)
189
- .stdin({ 'name' => 'test', 'num_tasks' => 1, 'lease_secs' => TASKQUEUE_LEASE_SECS })
190
- .stdout({ 'name' => 'log' })
191
- # app.run! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
192
- service_run! app
165
+ app = TQ::App.new(RelayWorker, queue_spec('test', 1), queue_out: queue_spec('log',1))
166
+ run! app
193
167
 
194
168
  sleep TASKQUEUE_LEASE_SECS + 1
195
- actual_output_tasks = clear_queue!(TASKQUEUE_PROJECT_ID,'log')
196
- actual_input_tasks = clear_queue!(TASKQUEUE_PROJECT_ID,'test')
169
+ actual_output_tasks = clear_queue!('log')
170
+ actual_input_tasks = clear_queue!('test')
197
171
 
198
172
  # assertion
199
173
 
@@ -203,153 +177,48 @@ class AppRunTests < Minitest::Spec
203
177
  assert_equal a = expected_tasks.length, b = actual_output_tasks.length,
204
178
  "Expected #{a} #{a == 1 ? 'task' : 'tasks'} on output queue, #{b < 2 ? 'was' : 'were'} #{b}"
205
179
 
180
+
206
181
  end
207
182
 
208
183
  it 'should extend a task lease if extended before lease expires' do
209
-
210
- refute true, "Extending task leases does not currently work"
211
184
 
212
185
  # setup
213
186
  expected_tasks = [
214
187
  { 'What is your name?' => 'Sir Lancelot', 'What is your quest?' => 'To seek the holy grail', 'What is your favorite color?' => 'blue' }
215
188
  ]
216
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
189
+ push_tasks!('test', expected_tasks)
217
190
 
218
191
  class ExtendWorker
192
+ include MiniTest::Assertions
193
+
194
+ attr_accessor :assertions
219
195
  def initialize(*args)
220
196
  @stdin = args.first
197
+ @assertions = 0
221
198
  end
222
199
 
223
200
  def call(task)
224
- $stderr.puts "ExtendWorker - task #{ task.raw.inspect }"
225
201
  ttl = task.lease_remaining
226
- # sleep( ttl - 0.5 )
227
- task = @stdin.extend!(task)
202
+ sleep( ttl - 0.5 )
203
+ task = task.extend!('3s')
228
204
  ttl2 = task.lease_remaining
229
205
  $stderr.puts "ExtendWorker - ttl before extend: #{ttl}"
230
206
  $stderr.puts "ExtendWorker - ttl after extend: #{ttl2}"
207
+ assert_in_delta( 2.5, ttl2, 0.07,
208
+ "Expected to be approximately 2.5s"
209
+ )
231
210
  end
232
211
  end
233
212
 
234
213
  # execution
235
- app = TQ::App.new('test_app/0.0.0', ExtendWorker)
236
- .project(TASKQUEUE_PROJECT_ID)
237
- .stdin({ 'name' => 'test', 'num_tasks' => 1, 'lease_secs' => TASKQUEUE_LEASE_SECS + 2 })
238
- # app.run! CLIENT_SECRETS_FILE, CREDENTIALS_FILE
239
- service_run! app
240
-
241
- end
242
-
243
- it 'should retry tasks indefinitely by default' do
244
-
245
- # setup
246
- expected_tasks = [
247
- { 'What is your name?' => 'Sir Lancelot', 'What is your quest?' => 'To seek the holy grail', 'What is your favorite color?' => 'blue' }
248
- ]
249
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
250
-
251
- # expectations
252
- mock_handler_class = MiniTest::Mock.new
253
- mock_handler = MiniTest::Mock.new
254
-
255
- ## expect constructor receives task queue as first param
256
- expected_calls = 3
257
- (0...expected_calls).each do
258
- mock_handler_class.expect(:new, mock_handler) do |*args|
259
- args.first.respond_to?('finish!')
260
- end
261
- end
262
-
263
- ## expect :call for each queued task up to expected_calls
264
- actual_calls = 0
265
- (0...expected_calls).each do
266
- mock_handler.expect(:call, true) do |actual_task|
267
- actual_calls += 1
268
- end
269
- end
270
-
271
- # execution
272
- app = TQ::App.new('test_app/0.0.0', mock_handler_class)
273
- .project(TASKQUEUE_PROJECT_ID)
274
- .stdin({ 'name' => 'test',
275
- 'num_tasks' => 1,
276
- 'lease_secs' => TASKQUEUE_LEASE_SECS
277
- })
278
- .stdout({ 'name' => 'log' })
214
+ app = TQ::App.new(ExtendWorker, queue_spec('test', 1))
215
+ run! app
279
216
 
280
- service_run! app
281
- sleep TASKQUEUE_LEASE_SECS + 1
282
- service_run! app
283
- sleep TASKQUEUE_LEASE_SECS + 1
284
- service_run! app
285
-
286
- # assertion
287
-
288
- assert_equal expected_calls, actual_calls,
289
- "Expected #{expected_calls} worker calls, was #{actual_calls}"
290
-
291
- mock_handler_class.verify
292
- mock_handler.verify
293
-
294
- end
295
-
296
- it 'should only run if current task retry count is less than queue max_tries' do
297
-
298
- # setup
299
- expected_tasks = [
300
- { 'What is your name?' => 'Sir Lancelot', 'What is your quest?' => 'To seek the holy grail', 'What is your favorite color?' => 'blue' }
301
- ]
302
- push_tasks!(TASKQUEUE_PROJECT_ID,'test', expected_tasks)
303
-
304
- # expectations
305
- mock_handler_class = MiniTest::Mock.new
306
- mock_handler = MiniTest::Mock.new
307
-
308
- ## expect constructor receives task queue as first param
309
- max_tries = 2
310
- expected_calls = max_tries
311
- (0...expected_calls).each do
312
- mock_handler_class.expect(:new, mock_handler) do |*args|
313
- args.first.respond_to?('finish!')
314
- end
315
- end
316
-
317
- ## expect :call for each queued task up to expected_calls
318
- actual_calls = 0
319
- (0...max_tries).each do
320
- mock_handler.expect(:call, true) do |actual_task|
321
- actual_calls += 1
322
- end
323
- end
324
-
325
- # execution
326
- app = TQ::App.new('test_app/0.0.0', mock_handler_class)
327
- .project(TASKQUEUE_PROJECT_ID)
328
- .stdin({ 'name' => 'test',
329
- 'num_tasks' => 1,
330
- 'lease_secs' => TASKQUEUE_LEASE_SECS,
331
- 'max_tries' => max_tries
332
- })
333
- .stdout({ 'name' => 'log' })
334
-
335
- service_run! app
336
- sleep TASKQUEUE_LEASE_SECS + 1
337
- service_run! app
338
- sleep TASKQUEUE_LEASE_SECS + 1
339
- service_run! app
340
-
341
- # assertion
342
- assert_equal expected_calls, actual_calls,
343
- "Expected #{expected_calls} worker calls, was #{actual_calls}"
344
-
345
- mock_handler_class.verify
346
- mock_handler.verify
347
-
348
217
  end
349
218
 
350
-
351
219
  end
352
220
 
353
221
  end
354
222
 
355
223
  setup_test_logger!
224
+