gearman-ruby 2.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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