gearman-ruby 2.0.0 → 3.0.1

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 (50) hide show
  1. data/Rakefile +5 -6
  2. data/VERSION.yml +2 -2
  3. data/examples/calculus_client.rb +8 -10
  4. data/examples/calculus_worker.rb +4 -1
  5. data/examples/client.php +23 -0
  6. data/examples/client.rb +6 -10
  7. data/examples/client_background.rb +7 -7
  8. data/examples/client_data.rb +4 -4
  9. data/examples/client_epoch.rb +23 -0
  10. data/examples/client_exception.rb +4 -2
  11. data/examples/client_prefix.rb +4 -2
  12. data/examples/client_reverse.rb +27 -0
  13. data/examples/scale_image.rb +4 -3
  14. data/examples/scale_image_worker.rb +1 -1
  15. data/examples/worker.rb +2 -4
  16. data/examples/worker_data.rb +2 -2
  17. data/examples/worker_exception.rb +1 -1
  18. data/examples/worker_prefix.rb +1 -1
  19. data/examples/worker_reverse_string.rb +27 -0
  20. data/examples/worker_reverse_to_file.rb +18 -0
  21. data/examples/{evented_worker.rb → worker_signals.rb} +18 -8
  22. data/lib/gearman.rb +68 -21
  23. data/lib/gearman/client.rb +137 -65
  24. data/lib/gearman/server.rb +4 -4
  25. data/lib/gearman/task.rb +140 -20
  26. data/lib/gearman/taskset.rb +280 -5
  27. data/lib/gearman/testlib.rb +95 -0
  28. data/lib/gearman/util.rb +184 -28
  29. data/lib/gearman/worker.rb +356 -20
  30. data/test/client_test.rb +145 -0
  31. data/test/mock_client_test.rb +629 -0
  32. data/test/mock_worker_test.rb +321 -0
  33. data/test/util_test.rb +8 -3
  34. data/test/worker_test.rb +50 -34
  35. metadata +41 -41
  36. data/examples/client_echo.rb +0 -16
  37. data/examples/evented_client.rb +0 -23
  38. data/examples/worker_echo.rb +0 -20
  39. data/examples/worker_echo_pprof.rb +0 -5
  40. data/gearman-ruby.gemspec +0 -111
  41. data/lib/gearman/evented/client.rb +0 -99
  42. data/lib/gearman/evented/reactor.rb +0 -86
  43. data/lib/gearman/evented/worker.rb +0 -118
  44. data/lib/gearman/job.rb +0 -38
  45. data/lib/gearman/protocol.rb +0 -110
  46. data/test/basic_integration_test.rb +0 -121
  47. data/test/crash_test.rb +0 -69
  48. data/test/job_test.rb +0 -30
  49. data/test/protocol_test.rb +0 -132
  50. data/test/test_helper.rb +0 -31
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift('../lib')
4
+ require 'gearman'
5
+ require 'gearman/testlib'
6
+ require 'test/unit'
7
+
8
+ class TestClient < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @server = FakeJobServer.new(self)
12
+ @server_b = FakeJobServer.new(self)
13
+ end
14
+
15
+ def teardown
16
+ @server.stop
17
+ end
18
+ ##
19
+ # Test the get_socket, return_socket, close_socket, and
20
+ # get_hostport_for_socket methods of Client.
21
+ def test_sockets
22
+ client = Gearman::Client.new
23
+ hostport = "localhost:#{@server.port}"
24
+ client.job_servers = [hostport]
25
+
26
+ # If we get a socket, return it, and request a socket for the same
27
+ # host, we should get the original one again.
28
+ origsock = client.get_socket(client.get_job_server)
29
+ client.return_socket(origsock)
30
+ assert_equal(origsock, client.get_socket(client.get_job_server))
31
+ assert_equal(hostport, client.get_hostport_for_socket(origsock))
32
+
33
+ # We should get another socket if we call get_socket again.
34
+ newsock = client.get_socket(client.get_job_server)
35
+ assert_not_equal(origsock, newsock)
36
+ assert_equal(hostport, client.get_hostport_for_socket(newsock))
37
+
38
+ # They should be closed when we call close_socket, and we should get
39
+ # a new socket the next time.
40
+ client.close_socket(origsock)
41
+ client.close_socket(newsock)
42
+ assert(origsock.closed?)
43
+ assert(newsock.closed?)
44
+ assert_not_equal(origsock, client.get_socket(client.get_job_server))
45
+ end
46
+
47
+ ##
48
+ # We check that the client does not fail if at least one
49
+ # server is up.
50
+ def test_first_connection_server_down_retry
51
+ client = Gearman::Client.new
52
+ hostport_good = "localhost:#{@server.port}"
53
+ hostport_bad = "nonexistent:8080"
54
+ # TODO: why does this fail?
55
+ # hostport_bad = "localhost:#{@server.port+x}" for x in (1..5)
56
+
57
+ client.job_servers = [hostport_bad,hostport_good]
58
+
59
+ first_requested_server = client.get_job_server
60
+ assert(first_requested_server == hostport_bad)
61
+
62
+ begin
63
+ result = client.get_socket(first_requested_server)
64
+ assert(false)
65
+ rescue RuntimeError
66
+ assert(true)
67
+ end
68
+
69
+ assert(client.bad_servers.size == 1)
70
+
71
+ second_requested_server = client.get_job_server
72
+ assert(second_requested_server == hostport_good)
73
+ begin
74
+ client.get_socket(second_requested_server)
75
+ assert(true)
76
+ rescue RuntimeError
77
+ assert(false)
78
+ end
79
+ end
80
+
81
+ ##
82
+ # We check that the client raises a fatal exception if server fails
83
+ # while connected.
84
+ def test_client_down_if_server_down
85
+ client = Gearman::Client.new
86
+ hostport_good = "localhost:#{@server.port}"
87
+ hostport_good_b = "localhost:#{@server_b.port}"
88
+
89
+ client.job_servers = [hostport_good,hostport_good_b]
90
+
91
+ # We simulate a gearmand server failure after receiving some data
92
+ # from the client
93
+ Thread.new do
94
+ server_socket = @server.expect_connection
95
+ @server.expect_anything_and_close_socket(server_socket)
96
+ end
97
+
98
+ taskset = Gearman::TaskSet.new(client)
99
+
100
+ task = Gearman::Task.new('sleep', 20)
101
+ task.on_complete {|d| puts d }
102
+
103
+ should_be_true = true
104
+ begin
105
+ taskset.add_task(task)
106
+ should_be_true = false
107
+ rescue Exception => ex
108
+ end
109
+ assert(should_be_true)
110
+ end
111
+
112
+ def test_option_request_exceptions
113
+ this_server = FakeJobServer.new(self)
114
+ Thread.new do
115
+ server_socket = this_server.expect_connection
116
+ this_server.expect_request(server_socket, "option_req", "exceptions")
117
+ this_server.send_response(server_socket, :job_created, 'a')
118
+ end
119
+ client = Gearman::Client.new
120
+ hostport = "localhost:#{this_server.port}"
121
+ client.job_servers = [hostport]
122
+ client.option_request("exceptions")
123
+ end
124
+
125
+ def test_option_request_bad
126
+ this_server = FakeJobServer.new(self)
127
+ Thread.new do
128
+ server_socket = this_server.expect_connection
129
+ this_server.expect_request(server_socket, "option_req", "cccceptionsccc")
130
+ this_server.send_response(server_socket, :exception, 'a')
131
+ end
132
+
133
+ client = Gearman::Client.new
134
+ hostport = "localhost:#{this_server.port}"
135
+ client.job_servers = [hostport]
136
+ begin
137
+ client.option_request("cccceptionsccc")
138
+ assert(false)
139
+ rescue Gearman::ProtocolError
140
+ assert(true)
141
+ end
142
+ end
143
+
144
+
145
+ end
@@ -0,0 +1,629 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift('../lib')
4
+ require 'gearman'
5
+ require 'gearman/testlib'
6
+ require 'test/unit'
7
+ require 'thread'
8
+
9
+ Thread.abort_on_exception = true
10
+
11
+ class TestClient < Test::Unit::TestCase
12
+ ##
13
+ # Do a simple test of the functionality of the client code.
14
+ def test_client
15
+ server = FakeJobServer.new(self)
16
+ client, task1, task2, taskset, sock, res1, res2 = nil
17
+
18
+ s = TestScript.new
19
+ c = TestScript.new
20
+
21
+ server_thread = Thread.new { s.loop_forever }.run
22
+ client_thread = Thread.new { c.loop_forever }.run
23
+
24
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
25
+
26
+ c.exec { task1 = Gearman::Task.new('add', '5 2') }
27
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
28
+ c.exec { taskset = Gearman::TaskSet.new(client) }
29
+ c.exec { taskset.add_task(task1) }
30
+ s.exec { sock = server.expect_connection }
31
+ s.wait
32
+
33
+ s.exec { server.expect_request(sock, :submit_job, "add\000\0005 2") }
34
+ s.exec { server.send_response(sock, :job_created, 'a') }
35
+
36
+ # Create a second task. It should use the same socket as the first.
37
+ c.exec { task2 = Gearman::Task.new('add', '10 5') }
38
+ c.exec { task2.on_complete {|d| res2 = d.to_i } }
39
+ c.exec { taskset.add_task(task2) }
40
+
41
+ # Return the response to the first job before the handle for the
42
+ # second.
43
+ s.exec { server.send_response(sock, :work_complete, "a\0007") }
44
+ s.exec { server.expect_request(sock, :submit_job, "add\000\00010 5") }
45
+ s.exec { server.send_response(sock, :job_created, 'b') }
46
+
47
+ # After the client waits on the taskset, send the response to the
48
+ # second job.
49
+ c.exec { taskset.wait }
50
+ s.exec { server.send_response(sock, :work_complete, "b\00015") }
51
+ c.wait
52
+ s.wait
53
+
54
+ # Check that we got the right answers.
55
+ assert_equal(7, res1)
56
+ assert_equal(15, res2)
57
+ end
58
+
59
+ ##
60
+ # Tests that the high priority option can be set in a job request
61
+ def test_client_submit_priority_high
62
+ server = FakeJobServer.new(self)
63
+ client, task1, task2, taskset, sock, res1, res2 = nil
64
+
65
+ s = TestScript.new
66
+ c = TestScript.new
67
+
68
+ server_thread = Thread.new { s.loop_forever }.run
69
+ client_thread = Thread.new { c.loop_forever }.run
70
+
71
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
72
+
73
+ c.exec { task1 = Gearman::Task.new('add', '5 2', { :priority => :high }) }
74
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
75
+ c.exec { taskset = Gearman::TaskSet.new(client) }
76
+ c.exec { taskset.add_task(task1) }
77
+ s.exec { sock = server.expect_connection }
78
+ s.wait
79
+
80
+ s.exec { server.expect_request(sock, :submit_job_high, "add\000\0005 2") }
81
+ end
82
+
83
+ ##
84
+ # Tests that the low priority option can be set in a job request
85
+ def test_client_submit_priority_low
86
+ server = FakeJobServer.new(self)
87
+ client, task1, task2, taskset, sock, res1, res2 = nil
88
+
89
+ s = TestScript.new
90
+ c = TestScript.new
91
+
92
+ server_thread = Thread.new { s.loop_forever }.run
93
+ client_thread = Thread.new { c.loop_forever }.run
94
+
95
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
96
+
97
+ c.exec { task1 = Gearman::Task.new('add', '5 2', { :priority => :low }) }
98
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
99
+ c.exec { taskset = Gearman::TaskSet.new(client) }
100
+ c.exec { taskset.add_task(task1) }
101
+ s.exec { sock = server.expect_connection }
102
+ s.wait
103
+
104
+ s.exec { server.expect_request(sock, :submit_job_low, "add\000\0005 2") }
105
+ end
106
+
107
+
108
+ ##
109
+ # Check that the client sends a correct background job request
110
+ def test_client_submit_background
111
+ server = FakeJobServer.new(self)
112
+ client, task1, task2, taskset, sock, res1, res2 = nil
113
+
114
+ s = TestScript.new
115
+ c = TestScript.new
116
+
117
+ server_thread = Thread.new { s.loop_forever }.run
118
+ client_thread = Thread.new { c.loop_forever }.run
119
+
120
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
121
+
122
+ c.exec { task1 = Gearman::Task.new('add', '5 2', { :background => :true }) }
123
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
124
+ c.exec { taskset = Gearman::TaskSet.new(client) }
125
+ c.exec { taskset.add_task(task1) }
126
+ s.exec { sock = server.expect_connection }
127
+ s.wait
128
+
129
+ s.exec { server.expect_request(sock, :submit_job_bg, "add\000\0005 2") }
130
+ end
131
+
132
+ ##
133
+ # Check that the client sends a correct background job with high priority request
134
+ def test_client_submit_background
135
+ server = FakeJobServer.new(self)
136
+ client, task1, task2, taskset, sock, res1, res2 = nil
137
+
138
+ s = TestScript.new
139
+ c = TestScript.new
140
+
141
+ server_thread = Thread.new { s.loop_forever }.run
142
+ client_thread = Thread.new { c.loop_forever }.run
143
+
144
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
145
+
146
+ c.exec { task1 = Gearman::Task.new('add', '5 2', { :background => :true, :priority => :high }) }
147
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
148
+ c.exec { taskset = Gearman::TaskSet.new(client) }
149
+ c.exec { taskset.add_task(task1) }
150
+ s.exec { sock = server.expect_connection }
151
+ s.wait
152
+
153
+ s.exec { server.expect_request(sock, :submit_job_high_bg, "add\000\0005 2") }
154
+ end
155
+
156
+ ##
157
+ # Check that the client sends a correct background job with low priority request
158
+ def test_client_submit_background
159
+ server = FakeJobServer.new(self)
160
+ client, task1, task2, taskset, sock, res1, res2 = nil
161
+
162
+ s = TestScript.new
163
+ c = TestScript.new
164
+
165
+ server_thread = Thread.new { s.loop_forever }.run
166
+ client_thread = Thread.new { c.loop_forever }.run
167
+
168
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
169
+
170
+ c.exec { task1 = Gearman::Task.new('add', '5 2', { :background => :true, :priority => :low }) }
171
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
172
+ c.exec { taskset = Gearman::TaskSet.new(client) }
173
+ c.exec { taskset.add_task(task1) }
174
+ s.exec { sock = server.expect_connection }
175
+ s.wait
176
+
177
+ s.exec { server.expect_request(sock, :submit_job_low_bg, "add\000\0005 2") }
178
+ end
179
+
180
+ ##
181
+ # Test Client#do_task.
182
+ def test_do_task
183
+ server = FakeJobServer.new(self)
184
+ client, sock, res = nil
185
+
186
+ s = TestScript.new
187
+ c = TestScript.new
188
+
189
+ server_thread = Thread.new { s.loop_forever }.run
190
+ client_thread = Thread.new { c.loop_forever }.run
191
+
192
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
193
+
194
+ c.exec { res = client.do_task('add', '5 2').to_i }
195
+ s.exec { sock = server.expect_connection }
196
+ s.wait
197
+
198
+ s.exec { server.expect_request(sock, :submit_job, "add\000\0005 2") }
199
+ s.exec { server.send_response(sock, :job_created, 'a') }
200
+ s.exec { server.send_response(sock, :work_complete, "a\0007") }
201
+ c.wait
202
+ s.wait
203
+
204
+ assert_equal(7, res)
205
+
206
+ c.exec { res = client.do_task('add', '1 2') }
207
+ s.exec { server.expect_request(sock, :submit_job, "add\000\0001 2") }
208
+ s.exec { server.send_response(sock, :job_created, 'a') }
209
+ s.exec { server.send_response(sock, :work_fail, 'a') }
210
+ c.wait
211
+ s.wait
212
+
213
+ assert_equal(nil, res)
214
+ end
215
+
216
+ ##
217
+ # Test that Gearman::Task's callback's get called when they should.
218
+ def test_callbacks
219
+ server = FakeJobServer.new(self)
220
+ client, task, taskset, sock = nil
221
+ failed, retries, num, den, warning = nil
222
+
223
+ s = TestScript.new
224
+ c = TestScript.new
225
+
226
+ server_thread = Thread.new { s.loop_forever }.run
227
+ client_thread = Thread.new { c.loop_forever }.run
228
+
229
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
230
+
231
+ task = Gearman::Task.new('foo', 'bar', { :retry_count => 3 })
232
+ task.on_fail { failed = true }
233
+ task.on_retry {|r| retries = r }
234
+ task.on_status {|n,d| num = n.to_i; den = d.to_i }
235
+ task.on_warning {|msg| warning = msg }
236
+ received_data = ""
237
+ task.on_data {|data| received_data << data }
238
+
239
+ c.exec { taskset = Gearman::TaskSet.new(client) }
240
+ c.exec { taskset.add_task(task) }
241
+ s.exec { sock = server.expect_connection }
242
+ s.wait
243
+
244
+ # Send 4 failures back to the client.
245
+ c.exec { taskset.wait }
246
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
247
+ s.exec { server.send_response(sock, :job_created, 'a') }
248
+ s.exec { server.send_response(sock, :work_fail, 'a') }
249
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
250
+ s.exec { server.send_response(sock, :job_created, 'b') }
251
+ s.exec { server.send_response(sock, :work_fail, 'b') }
252
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
253
+ s.exec { server.send_response(sock, :job_created, 'c') }
254
+ s.exec { server.send_response(sock, :work_status, "c\0001\0002") }
255
+ s.exec { server.send_response(sock, :work_fail, 'c') }
256
+ s.exec { server.send_response(sock, :job_created, 'd') }
257
+ s.exec { server.send_response(sock, :work_data, "d\000data chunk 1") }
258
+ s.exec { server.send_response(sock, :work_data, "d\000data chunk 2") }
259
+ s.exec { server.send_response(sock, :work_warning, "d\000warning") }
260
+ s.exec { server.send_response(sock, :work_fail, 'd') }
261
+ c.wait
262
+ s.wait
263
+
264
+ assert_equal(true, failed)
265
+ assert_equal(3, retries)
266
+ assert_equal(1, num)
267
+ assert_equal(2, den)
268
+ assert_equal("data chunk 1data chunk 2", received_data)
269
+ assert_equal("warning", warning)
270
+ end
271
+
272
+ def test_failure
273
+ server = FakeJobServer.new(self)
274
+ client, task1, task2, taskset, sock = nil
275
+ res1, res2, fail1, fail2, setres = nil
276
+
277
+ s = TestScript.new
278
+ c = TestScript.new
279
+
280
+ server_thread = Thread.new { s.loop_forever }.run
281
+ client_thread = Thread.new { c.loop_forever }.run
282
+
283
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
284
+
285
+ c.exec { task1 = Gearman::Task.new('func1', 'a') }
286
+ c.exec { task1.on_complete {|d| res1 = d } }
287
+ c.exec { task1.on_fail { fail1 = true } }
288
+ c.exec { taskset = Gearman::TaskSet.new(client) }
289
+ c.exec { taskset.add_task(task1) }
290
+ s.exec { sock = server.expect_connection }
291
+ s.wait
292
+
293
+ s.exec { server.expect_request(sock, :submit_job, "func1\000\000a") }
294
+ s.exec { server.send_response(sock, :job_created, 'a') }
295
+
296
+ c.exec { task2 = Gearman::Task.new('func2', 'b') }
297
+ c.exec { task2.on_complete {|d| res2 = d } }
298
+ c.exec { task2.on_fail { fail2 = true } }
299
+ c.exec { taskset.add_task(task2) }
300
+
301
+ s.exec { server.expect_request(sock, :submit_job, "func2\000\000b") }
302
+ s.exec { server.send_response(sock, :job_created, 'b') }
303
+
304
+ s.exec { server.send_response(sock, :work_complete, "a\000a1") }
305
+ s.exec { server.send_response(sock, :work_fail, "b") }
306
+
307
+ c.exec { setres = taskset.wait }
308
+ c.wait
309
+ s.wait
310
+
311
+ assert_equal('a1', res1)
312
+ assert_equal(nil, res2)
313
+ assert_equal(nil, fail1)
314
+ assert_equal(true, fail2)
315
+ assert_equal(false, setres)
316
+ end
317
+
318
+ def test_exception
319
+ server = FakeJobServer.new(self)
320
+ client, task, taskset, sock = nil
321
+ res,exception, setres = nil
322
+
323
+ s = TestScript.new
324
+ c = TestScript.new
325
+
326
+ server_thread = Thread.new { s.loop_forever }.run
327
+ client_thread = Thread.new { c.loop_forever }.run
328
+
329
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
330
+
331
+ c.exec { task = Gearman::Task.new('func2', 'b') }
332
+ c.exec { task.on_complete {|d| res = d } }
333
+ c.exec { task.on_exception {|message| exception=message; false } }
334
+ c.exec { taskset = Gearman::TaskSet.new(client) }
335
+ c.exec { taskset.add_task(task) }
336
+ s.exec { sock = server.expect_connection }
337
+
338
+ s.exec { server.expect_request(sock, :submit_job, "func2\000\000b") }
339
+ s.exec { server.send_response(sock, :job_created, 'b') }
340
+
341
+ s.exec { server.send_response(sock, :work_exception, "b\0exceptionmsg") }
342
+
343
+ c.exec { setres = taskset.wait }
344
+ c.wait
345
+ s.wait
346
+
347
+ assert_equal(nil, res)
348
+ assert_equal('exceptionmsg',exception)
349
+ end
350
+
351
+ ##
352
+ # Test that user-supplied uniq values are handled correctly.
353
+ def test_uniq
354
+ server1 = FakeJobServer.new(self)
355
+ server2 = FakeJobServer.new(self)
356
+ client = nil
357
+ sock1, sock2 = nil
358
+ taskset = nil
359
+ task1, task2, task3, task4 = nil
360
+ res1, res2, res3, res4 = nil
361
+ hostport1 = "localhost:#{server1.port}"
362
+ hostport2 = "localhost:#{server2.port}"
363
+
364
+ s1 = TestScript.new
365
+ s2 = TestScript.new
366
+ c = TestScript.new
367
+
368
+ server1_thread = Thread.new { s1.loop_forever }.run
369
+ server2_thread = Thread.new { s2.loop_forever }.run
370
+ client_thread = Thread.new { c.loop_forever }.run
371
+
372
+ c.exec { client = Gearman::Client.new }
373
+ c.exec { client.job_servers = [hostport1, hostport2] }
374
+ c.exec { taskset = Gearman::TaskSet.new(client) }
375
+
376
+ # Submit a task with uniq key 'u' to the first server.
377
+ c.exec { client.test_hostport = hostport1 }
378
+ c.exec { task1 = Gearman::Task.new('func1', 'arg', { :uniq => 'u' }) }
379
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
380
+ c.exec { taskset.add_task(task1) }
381
+
382
+ s1.exec { sock1 = server1.expect_connection }
383
+ s1.wait
384
+
385
+ s1.exec { server1.expect_request(
386
+ sock1, :submit_job, "func1\000#{'u'.hash}\000arg") }
387
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
388
+
389
+ # If we submit a second task with the same key, it should get sent to
390
+ # the same server.
391
+ c.exec { client.test_hostport = hostport2 }
392
+ c.exec { task2 = Gearman::Task.new('func1', 'arg2', { :uniq => 'u' }) }
393
+ c.exec { task2.on_complete {|d| res2 = d.to_i } }
394
+ c.exec { taskset.add_task(task2) }
395
+
396
+ s1.exec { server1.expect_request(
397
+ sock1, :submit_job, "func1\000#{'u'.hash}\000arg2") }
398
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
399
+
400
+ # When we create a task with key 'a', it should go to the second
401
+ # server.
402
+ c.exec { task3 = Gearman::Task.new('func1', 'arg', { :uniq => 'a' }) }
403
+ c.exec { task3.on_complete {|d| res3 = d.to_i } }
404
+ c.exec { taskset.add_task(task3) }
405
+
406
+ s2.exec { sock2 = server2.expect_connection }
407
+ s2.wait
408
+
409
+ s2.exec { server2.expect_request(
410
+ sock2, :submit_job, "func1\000#{'a'.hash}\000arg") }
411
+ s2.exec { server2.send_response(sock2, :job_created, 'b') }
412
+
413
+ # If we tell the client to use the first server again and create
414
+ # another job with no uniq key, it should go back to the first server.
415
+ c.exec { client.test_hostport = hostport1 }
416
+ c.exec { task4 = Gearman::Task.new('func1', 'arg') }
417
+ c.exec { task4.on_complete {|d| res4 = d.to_i } }
418
+ c.exec { taskset.add_task(task4) }
419
+
420
+ s1.exec { server1.expect_request(
421
+ sock1, :submit_job, "func1\000\000arg") }
422
+ s1.exec { server1.send_response(sock1, :job_created, 'c') }
423
+
424
+ # Send back responses for all the handles we've handed out and make
425
+ # sure that we got what we expected.
426
+ c.exec { taskset.wait }
427
+ s1.exec { server1.send_response(sock1, :work_complete, "a\0001") }
428
+ s2.exec { server2.send_response(sock2, :work_complete, "b\0002") }
429
+ s1.exec { server1.send_response(sock1, :work_complete, "c\0003") }
430
+
431
+ c.wait
432
+ s1.wait
433
+ s2.wait
434
+
435
+ assert_equal(1, res1)
436
+ assert_equal(1, res2)
437
+ assert_equal(2, res3)
438
+ assert_equal(3, res4)
439
+
440
+ c.wait
441
+ s1.wait
442
+ s2.wait
443
+ end
444
+
445
+ ##
446
+ # Test that '-' uniq values work correctly.
447
+ def test_uniq_dash
448
+ server1 = FakeJobServer.new(self)
449
+ server2 = FakeJobServer.new(self)
450
+ client, taskset, sock1, sock2 = nil
451
+ task1, task2, task3 = nil
452
+ res1, res2, res3 = nil
453
+ hostport1 = "localhost:#{server1.port}"
454
+ hostport2 = "localhost:#{server2.port}"
455
+
456
+ s1 = TestScript.new
457
+ s2 = TestScript.new
458
+ c = TestScript.new
459
+
460
+ server1_thread = Thread.new { s1.loop_forever }.run
461
+ server2_thread = Thread.new { s2.loop_forever }.run
462
+ client_thread = Thread.new { c.loop_forever }.run
463
+
464
+ c.exec { client = Gearman::Client.new }
465
+ c.exec { client.job_servers = [hostport1, hostport2] }
466
+ c.exec { taskset = Gearman::TaskSet.new(client) }
467
+
468
+ # The first task uses uniq = '-' with the argument 'arg'.
469
+ c.exec { client.test_hostport = hostport1 }
470
+ c.exec { task1 = Gearman::Task.new('func1', 'arg', { :uniq => '-' }) }
471
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
472
+ c.exec { taskset.add_task(task1) }
473
+
474
+ s1.exec { sock1 = server1.expect_connection }
475
+ s1.wait
476
+
477
+ s1.exec { server1.expect_request(
478
+ sock1, :submit_job, "func1\000#{'arg'.hash}\000arg") }
479
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
480
+
481
+ # The second task uses the same arg, so it should be merged with the
482
+ # first by the server (and also be executed on the first server, even
483
+ # though we've changed the client to use the second by default).
484
+ c.exec { client.test_hostport = hostport2 }
485
+ c.exec { task2 = Gearman::Task.new('func1', 'arg', { :uniq => '-' }) }
486
+ c.exec { task2.on_complete {|d| res2 = d.to_i } }
487
+ c.exec { taskset.add_task(task2) }
488
+
489
+ s1.exec { server1.expect_request(
490
+ sock1, :submit_job, "func1\000#{'arg'.hash}\000arg") }
491
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
492
+
493
+ # The third task uses 'arg2', so it should not be merged and instead
494
+ # run on the second server.
495
+ c.exec { task3 = Gearman::Task.new('func1', 'arg2', { :uniq => '-' }) }
496
+ c.exec { task3.on_complete {|d| res3 = d.to_i } }
497
+ c.exec { taskset.add_task(task3) }
498
+
499
+ s2.exec { sock2 = server2.expect_connection }
500
+ s2.wait
501
+
502
+ s2.exec { server2.expect_request(
503
+ sock2, :submit_job, "func1\000#{'arg2'.hash}\000arg2") }
504
+ s2.exec { server2.send_response(sock2, :job_created, 'b') }
505
+
506
+ # Send back results for the two handles that we've handed out.
507
+ c.exec { taskset.wait }
508
+ s1.exec { server1.send_response(sock1, :work_complete, "a\0001") }
509
+ s2.exec { server2.send_response(sock2, :work_complete, "b\0002") }
510
+
511
+ c.wait
512
+ s1.wait
513
+ s2.wait
514
+
515
+ assert_equal(1, res1)
516
+ assert_equal(1, res2)
517
+ assert_equal(2, res3)
518
+ end
519
+
520
+ ##
521
+ # Test that NUL bytes in returned data are preserved.
522
+ def test_nuls_in_data
523
+ server = FakeJobServer.new(self)
524
+ client, sock, res = nil
525
+
526
+ s = TestScript.new
527
+ c = TestScript.new
528
+
529
+ server_thread = Thread.new { s.loop_forever }.run
530
+ client_thread = Thread.new { c.loop_forever }.run
531
+
532
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
533
+
534
+ c.exec { res = client.do_task('foo', nil) }
535
+ s.exec { sock = server.expect_connection }
536
+ s.wait
537
+
538
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000") }
539
+ s.exec { server.send_response(sock, :job_created, 'a') }
540
+ s.exec { server.send_response(sock, :work_complete, "a\0001\0002\0003") }
541
+ c.wait
542
+ s.wait
543
+
544
+ assert_equal("1\0002\0003", res)
545
+ end
546
+
547
+ ##
548
+ # Test that clients time out when the server sends a partial packet and
549
+ # then hangs.
550
+ def test_read_timeouts
551
+ server = FakeJobServer.new(self)
552
+ client, sock, task, taskset, res = nil
553
+
554
+ s = TestScript.new
555
+ c = TestScript.new
556
+
557
+ server_thread = Thread.new { s.loop_forever }.run
558
+ client_thread = Thread.new { c.loop_forever }.run
559
+
560
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
561
+
562
+ # First, create a new task. The server claims to be sending back a
563
+ # packet with 1 byte of data, but actually sends an empty packet. The
564
+ # client should time out after 0.1 sec.
565
+ c.exec { taskset = Gearman::TaskSet.new(client) }
566
+ c.exec { task = Gearman::Task.new('foo', 'bar') }
567
+ c.exec { client.task_create_timeout_sec = 0.1 }
568
+ c.exec { res = taskset.add_task(task) }
569
+ s.exec { sock = server.expect_connection }
570
+ s.wait
571
+
572
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
573
+ s.exec { server.send_response(sock, :job_created, '', 1) }
574
+ c.wait
575
+ s.wait
576
+
577
+ assert_equal(false, res)
578
+
579
+ # Now create a task, but only return a partial packet for
580
+ # work_complete. The client should again time out after 0.1 sec.
581
+ c.exec { res = taskset.add_task(task) }
582
+ s.exec { sock = server.expect_connection }
583
+ s.wait
584
+
585
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
586
+ s.exec { server.send_response(sock, :job_created, 'a') }
587
+ c.exec { res = taskset.wait(0.1) }
588
+ s.exec { server.send_response(sock, :work_complete, "a\000", 3) }
589
+ c.wait
590
+ s.wait
591
+
592
+ assert_equal(false, res)
593
+ end
594
+
595
+ ##
596
+ # Tests partial data responses (work_data)
597
+ def test_chunked_data
598
+ server = FakeJobServer.new(self)
599
+ client, sock, task, taskset, res = nil
600
+
601
+ s = TestScript.new
602
+ c = TestScript.new
603
+
604
+ server_thread = Thread.new { s.loop_forever }.run
605
+ client_thread = Thread.new { c.loop_forever }.run
606
+
607
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
608
+ task = Gearman::Task.new('foo', 'bar', { :retry_count => 3 })
609
+ received_data = ""
610
+ task.on_data {|data| received_data << data }
611
+ task.on_complete {|data| received_data << data}
612
+
613
+ c.exec { taskset = Gearman::TaskSet.new(client) }
614
+ c.exec { taskset.add_task(task) }
615
+ s.exec { sock = server.expect_connection }
616
+ s.wait
617
+
618
+ c.exec { taskset.wait }
619
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
620
+ s.exec { server.send_response(sock, :job_created, 'a') }
621
+ s.exec { server.send_response(sock, :work_data, "a\000data chunk 1\n") }
622
+ s.exec { server.send_response(sock, :work_data, "a\000data chunk 2\n") }
623
+ s.exec { server.send_response(sock, :work_complete, "a\000data complete") }
624
+ c.wait
625
+ s.wait
626
+
627
+ assert_equal("data chunk 1\ndata chunk 2\ndata complete", received_data)
628
+ end
629
+ end