xing-gearman-ruby 1.0.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.
@@ -0,0 +1,111 @@
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
+ end
@@ -0,0 +1,431 @@
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
+ # Test Client#do_task.
61
+ def test_do_task
62
+ server = FakeJobServer.new(self)
63
+ client, sock, res = 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 { res = client.do_task('add', '5 2').to_i }
74
+ s.exec { sock = server.expect_connection }
75
+ s.wait
76
+
77
+ s.exec { server.expect_request(sock, :submit_job, "add\000\0005 2") }
78
+ s.exec { server.send_response(sock, :job_created, 'a') }
79
+ s.exec { server.send_response(sock, :work_complete, "a\0007") }
80
+ c.wait
81
+ s.wait
82
+
83
+ assert_equal(7, res)
84
+
85
+ c.exec { res = client.do_task('add', '1 2') }
86
+ s.exec { server.expect_request(sock, :submit_job, "add\000\0001 2") }
87
+ s.exec { server.send_response(sock, :job_created, 'a') }
88
+ s.exec { server.send_response(sock, :work_fail, 'a') }
89
+ c.wait
90
+ s.wait
91
+
92
+ assert_equal(nil, res)
93
+ end
94
+
95
+ ##
96
+ # Test that Gearman::Task's callback's get called when they should.
97
+ def test_callbacks
98
+ server = FakeJobServer.new(self)
99
+ client, task, taskset, sock = nil
100
+ failed, retries, num, den = nil
101
+
102
+ s = TestScript.new
103
+ c = TestScript.new
104
+
105
+ server_thread = Thread.new { s.loop_forever }.run
106
+ client_thread = Thread.new { c.loop_forever }.run
107
+
108
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
109
+
110
+ task = Gearman::Task.new('foo', 'bar',
111
+ { :retry_count => 2 })
112
+ task.on_fail { failed = true }
113
+ task.on_retry {|r| retries = r }
114
+ task.on_status {|n,d| num = n.to_i; den = d.to_i }
115
+
116
+ c.exec { taskset = Gearman::TaskSet.new(client) }
117
+ c.exec { taskset.add_task(task) }
118
+ s.exec { sock = server.expect_connection }
119
+ s.wait
120
+
121
+ # Send three failures back to the client.
122
+ c.exec { taskset.wait }
123
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
124
+ s.exec { server.send_response(sock, :job_created, 'a') }
125
+ s.exec { server.send_response(sock, :work_fail, 'a') }
126
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
127
+ s.exec { server.send_response(sock, :job_created, 'b') }
128
+ s.exec { server.send_response(sock, :work_fail, 'b') }
129
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
130
+ s.exec { server.send_response(sock, :job_created, 'c') }
131
+ s.exec { server.send_response(sock, :work_status, "c\0001\0002") }
132
+ s.exec { server.send_response(sock, :work_fail, 'c') }
133
+ c.wait
134
+ s.wait
135
+
136
+ assert_equal(true, failed)
137
+ assert_equal(2, retries)
138
+ assert_equal(1, num)
139
+ assert_equal(2, den)
140
+ end
141
+
142
+ def test_failure
143
+ server = FakeJobServer.new(self)
144
+ client, task1, task2, taskset, sock = nil
145
+ res1, res2, fail1, fail2, setres = nil
146
+
147
+ s = TestScript.new
148
+ c = TestScript.new
149
+
150
+ server_thread = Thread.new { s.loop_forever }.run
151
+ client_thread = Thread.new { c.loop_forever }.run
152
+
153
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
154
+
155
+ c.exec { task1 = Gearman::Task.new('func1', 'a') }
156
+ c.exec { task1.on_complete {|d| res1 = d } }
157
+ c.exec { task1.on_fail { fail1 = true } }
158
+ c.exec { taskset = Gearman::TaskSet.new(client) }
159
+ c.exec { taskset.add_task(task1) }
160
+ s.exec { sock = server.expect_connection }
161
+ s.wait
162
+
163
+ s.exec { server.expect_request(sock, :submit_job, "func1\000\000a") }
164
+ s.exec { server.send_response(sock, :job_created, 'a') }
165
+
166
+ c.exec { task2 = Gearman::Task.new('func2', 'b') }
167
+ c.exec { task2.on_complete {|d| res2 = d } }
168
+ c.exec { task2.on_fail { fail2 = true } }
169
+ c.exec { taskset.add_task(task2) }
170
+
171
+ s.exec { server.expect_request(sock, :submit_job, "func2\000\000b") }
172
+ s.exec { server.send_response(sock, :job_created, 'b') }
173
+
174
+ s.exec { server.send_response(sock, :work_complete, "a\000a1") }
175
+ s.exec { server.send_response(sock, :work_fail, "b") }
176
+
177
+ c.exec { setres = taskset.wait }
178
+ c.wait
179
+ s.wait
180
+
181
+ assert_equal('a1', res1)
182
+ assert_equal(nil, res2)
183
+ assert_equal(nil, fail1)
184
+ assert_equal(true, fail2)
185
+ assert_equal(false, setres)
186
+ end
187
+
188
+ ##
189
+ # Test that user-supplied uniq values are handled correctly.
190
+ def test_uniq
191
+ server1 = FakeJobServer.new(self)
192
+ server2 = FakeJobServer.new(self)
193
+ client = nil
194
+ sock1, sock2 = nil
195
+ taskset = nil
196
+ task1, task2, task3, task4 = nil
197
+ res1, res2, res3, res4 = nil
198
+ hostport1 = "localhost:#{server1.port}"
199
+ hostport2 = "localhost:#{server2.port}"
200
+
201
+ s1 = TestScript.new
202
+ s2 = TestScript.new
203
+ c = TestScript.new
204
+
205
+ server1_thread = Thread.new { s1.loop_forever }.run
206
+ server2_thread = Thread.new { s2.loop_forever }.run
207
+ client_thread = Thread.new { c.loop_forever }.run
208
+
209
+ c.exec { client = Gearman::Client.new }
210
+ c.exec { client.job_servers = [hostport1, hostport2] }
211
+ c.exec { taskset = Gearman::TaskSet.new(client) }
212
+
213
+ # Submit a task with uniq key 'u' to the first server.
214
+ c.exec { client.test_hostport = hostport1 }
215
+ c.exec { task1 = Gearman::Task.new('func1', 'arg', { :uniq => 'u' }) }
216
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
217
+ c.exec { taskset.add_task(task1) }
218
+
219
+ s1.exec { sock1 = server1.expect_connection }
220
+ s1.wait
221
+
222
+ s1.exec { server1.expect_request(
223
+ sock1, :submit_job, "func1\000#{'u'.hash}\000arg") }
224
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
225
+
226
+ # If we submit a second task with the same key, it should get sent to
227
+ # the same server.
228
+ c.exec { client.test_hostport = hostport2 }
229
+ c.exec { task2 = Gearman::Task.new('func1', 'arg2', { :uniq => 'u' }) }
230
+ c.exec { task2.on_complete {|d| res2 = d.to_i } }
231
+ c.exec { taskset.add_task(task2) }
232
+
233
+ s1.exec { server1.expect_request(
234
+ sock1, :submit_job, "func1\000#{'u'.hash}\000arg2") }
235
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
236
+
237
+ # When we create a task with key 'a', it should go to the second
238
+ # server.
239
+ c.exec { task3 = Gearman::Task.new('func1', 'arg', { :uniq => 'a' }) }
240
+ c.exec { task3.on_complete {|d| res3 = d.to_i } }
241
+ c.exec { taskset.add_task(task3) }
242
+
243
+ s2.exec { sock2 = server2.expect_connection }
244
+ s2.wait
245
+
246
+ s2.exec { server2.expect_request(
247
+ sock2, :submit_job, "func1\000#{'a'.hash}\000arg") }
248
+ s2.exec { server2.send_response(sock2, :job_created, 'b') }
249
+
250
+ # If we tell the client to use the first server again and create
251
+ # another job with no uniq key, it should go back to the first server.
252
+ c.exec { client.test_hostport = hostport1 }
253
+ c.exec { task4 = Gearman::Task.new('func1', 'arg') }
254
+ c.exec { task4.on_complete {|d| res4 = d.to_i } }
255
+ c.exec { taskset.add_task(task4) }
256
+
257
+ s1.exec { server1.expect_request(
258
+ sock1, :submit_job, "func1\000\000arg") }
259
+ s1.exec { server1.send_response(sock1, :job_created, 'c') }
260
+
261
+ # Send back responses for all the handles we've handed out and make
262
+ # sure that we got what we expected.
263
+ c.exec { taskset.wait }
264
+ s1.exec { server1.send_response(sock1, :work_complete, "a\0001") }
265
+ s2.exec { server2.send_response(sock2, :work_complete, "b\0002") }
266
+ s1.exec { server1.send_response(sock1, :work_complete, "c\0003") }
267
+
268
+ c.wait
269
+ s1.wait
270
+ s2.wait
271
+
272
+ assert_equal(1, res1)
273
+ assert_equal(1, res2)
274
+ assert_equal(2, res3)
275
+ assert_equal(3, res4)
276
+
277
+ c.wait
278
+ s1.wait
279
+ s2.wait
280
+ end
281
+
282
+ ##
283
+ # Test that '-' uniq values work correctly.
284
+ def test_uniq_dash
285
+ server1 = FakeJobServer.new(self)
286
+ server2 = FakeJobServer.new(self)
287
+ client, taskset, sock1, sock2 = nil
288
+ task1, task2, task3 = nil
289
+ res1, res2, res3 = nil
290
+ hostport1 = "localhost:#{server1.port}"
291
+ hostport2 = "localhost:#{server2.port}"
292
+
293
+ s1 = TestScript.new
294
+ s2 = TestScript.new
295
+ c = TestScript.new
296
+
297
+ server1_thread = Thread.new { s1.loop_forever }.run
298
+ server2_thread = Thread.new { s2.loop_forever }.run
299
+ client_thread = Thread.new { c.loop_forever }.run
300
+
301
+ c.exec { client = Gearman::Client.new }
302
+ c.exec { client.job_servers = [hostport1, hostport2] }
303
+ c.exec { taskset = Gearman::TaskSet.new(client) }
304
+
305
+ # The first task uses uniq = '-' with the argument 'arg'.
306
+ c.exec { client.test_hostport = hostport1 }
307
+ c.exec { task1 = Gearman::Task.new('func1', 'arg', { :uniq => '-' }) }
308
+ c.exec { task1.on_complete {|d| res1 = d.to_i } }
309
+ c.exec { taskset.add_task(task1) }
310
+
311
+ s1.exec { sock1 = server1.expect_connection }
312
+ s1.wait
313
+
314
+ s1.exec { server1.expect_request(
315
+ sock1, :submit_job, "func1\000#{'arg'.hash}\000arg") }
316
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
317
+
318
+ # The second task uses the same arg, so it should be merged with the
319
+ # first by the server (and also be executed on the first server, even
320
+ # though we've changed the client to use the second by default).
321
+ c.exec { client.test_hostport = hostport2 }
322
+ c.exec { task2 = Gearman::Task.new('func1', 'arg', { :uniq => '-' }) }
323
+ c.exec { task2.on_complete {|d| res2 = d.to_i } }
324
+ c.exec { taskset.add_task(task2) }
325
+
326
+ s1.exec { server1.expect_request(
327
+ sock1, :submit_job, "func1\000#{'arg'.hash}\000arg") }
328
+ s1.exec { server1.send_response(sock1, :job_created, 'a') }
329
+
330
+ # The third task uses 'arg2', so it should not be merged and instead
331
+ # run on the second server.
332
+ c.exec { task3 = Gearman::Task.new('func1', 'arg2', { :uniq => '-' }) }
333
+ c.exec { task3.on_complete {|d| res3 = d.to_i } }
334
+ c.exec { taskset.add_task(task3) }
335
+
336
+ s2.exec { sock2 = server2.expect_connection }
337
+ s2.wait
338
+
339
+ s2.exec { server2.expect_request(
340
+ sock2, :submit_job, "func1\000#{'arg2'.hash}\000arg2") }
341
+ s2.exec { server2.send_response(sock2, :job_created, 'b') }
342
+
343
+ # Send back results for the two handles that we've handed out.
344
+ c.exec { taskset.wait }
345
+ s1.exec { server1.send_response(sock1, :work_complete, "a\0001") }
346
+ s2.exec { server2.send_response(sock2, :work_complete, "b\0002") }
347
+
348
+ c.wait
349
+ s1.wait
350
+ s2.wait
351
+
352
+ assert_equal(1, res1)
353
+ assert_equal(1, res2)
354
+ assert_equal(2, res3)
355
+ end
356
+
357
+ ##
358
+ # Test that NUL bytes in returned data are preserved.
359
+ def test_nuls_in_data
360
+ server = FakeJobServer.new(self)
361
+ client, sock, res = nil
362
+
363
+ s = TestScript.new
364
+ c = TestScript.new
365
+
366
+ server_thread = Thread.new { s.loop_forever }.run
367
+ client_thread = Thread.new { c.loop_forever }.run
368
+
369
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
370
+
371
+ c.exec { res = client.do_task('foo', nil) }
372
+ s.exec { sock = server.expect_connection }
373
+ s.wait
374
+
375
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000") }
376
+ s.exec { server.send_response(sock, :job_created, 'a') }
377
+ s.exec { server.send_response(sock, :work_complete, "a\0001\0002\0003") }
378
+ c.wait
379
+ s.wait
380
+
381
+ assert_equal("1\0002\0003", res)
382
+ end
383
+
384
+ ##
385
+ # Test that clients time out when the server sends a partial packet and
386
+ # then hangs.
387
+ def test_read_timeouts
388
+ server = FakeJobServer.new(self)
389
+ client, sock, task, taskset, res = nil
390
+
391
+ s = TestScript.new
392
+ c = TestScript.new
393
+
394
+ server_thread = Thread.new { s.loop_forever }.run
395
+ client_thread = Thread.new { c.loop_forever }.run
396
+
397
+ c.exec { client = Gearman::Client.new("localhost:#{server.port}") }
398
+
399
+ # First, create a new task. The server claims to be sending back a
400
+ # packet with 1 byte of data, but actually sends an empty packet. The
401
+ # client should time out after 0.1 sec.
402
+ c.exec { taskset = Gearman::TaskSet.new(client) }
403
+ c.exec { task = Gearman::Task.new('foo', 'bar') }
404
+ c.exec { client.task_create_timeout_sec = 0.1 }
405
+ c.exec { res = taskset.add_task(task) }
406
+ s.exec { sock = server.expect_connection }
407
+ s.wait
408
+
409
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
410
+ s.exec { server.send_response(sock, :job_created, '', 1) }
411
+ c.wait
412
+ s.wait
413
+
414
+ assert_equal(false, res)
415
+
416
+ # Now create a task, but only return a partial packet for
417
+ # work_complete. The client should again time out after 0.1 sec.
418
+ c.exec { res = taskset.add_task(task) }
419
+ s.exec { sock = server.expect_connection }
420
+ s.wait
421
+
422
+ s.exec { server.expect_request(sock, :submit_job, "foo\000\000bar") }
423
+ s.exec { server.send_response(sock, :job_created, 'a') }
424
+ c.exec { res = taskset.wait(0.1) }
425
+ s.exec { server.send_response(sock, :work_complete, "a\000", 3) }
426
+ c.wait
427
+ s.wait
428
+
429
+ assert_equal(false, res)
430
+ end
431
+ end