xing-gearman-ruby 1.0.0

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