Skip to content

Commit d910234

Browse files
committed
more tests and fixes for response processing bugs
1 parent 2fcb360 commit d910234

File tree

4 files changed

+224
-33
lines changed

4 files changed

+224
-33
lines changed

Beanstalk.Client.Test/BeanstalkProtocolTests.cs

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
using System;
21+
using Droog.Beanstalk.Client.Protocol;
2122
using NUnit.Framework;
2223
using System.Linq;
2324

@@ -40,6 +41,101 @@ public void Dispose_disconnects_from_server() {
4041
Assert.AreEqual(1, _mockSocket.CloseCalled);
4142
}
4243

44+
[Test]
45+
public void Socket_disconnection_disposes_client() {
46+
Assert.IsFalse(_client.IsDisposed);
47+
_mockSocket.Connected = false;
48+
Assert.IsTrue(_client.IsDisposed);
49+
}
50+
51+
[Test]
52+
public void Network_operation_on_disposed_client_throws() {
53+
_mockSocket.Connected = false;
54+
try {
55+
_client.CurrentTube = "bob";
56+
Assert.Fail("didn't throw");
57+
} catch(ObjectDisposedException) {
58+
return;
59+
} catch(Exception e) {
60+
Assert.Fail(string.Format("threw '{0}' instead of ObjectDisposedException", e));
61+
}
62+
}
63+
64+
[Test]
65+
public void Out_of_memory_response_throws() {
66+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "OUT_OF_MEMORY\r\n");
67+
var data = "foo".AsStream();
68+
try {
69+
_client.Put(0, TimeSpan.Zero, TimeSpan.Zero, data, data.Length);
70+
Assert.Fail("didn't throw");
71+
} catch(InvalidStatusException e) {
72+
Assert.AreEqual(ResponseStatus.OutOfMemory, e.Status);
73+
return;
74+
} catch(Exception e) {
75+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
76+
}
77+
}
78+
79+
[Test]
80+
public void Internal_error_response_throws() {
81+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "INTERNAL_ERROR\r\n");
82+
var data = "foo".AsStream();
83+
try {
84+
_client.Put(0, TimeSpan.Zero, TimeSpan.Zero, data, data.Length);
85+
Assert.Fail("didn't throw");
86+
} catch(InvalidStatusException e) {
87+
Assert.AreEqual(ResponseStatus.InternalError, e.Status);
88+
return;
89+
} catch(Exception e) {
90+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
91+
}
92+
}
93+
94+
[Test]
95+
public void Draining_response_throws() {
96+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "DRAINING\r\n");
97+
var data = "foo".AsStream();
98+
try {
99+
_client.Put(0, TimeSpan.Zero, TimeSpan.Zero, data, data.Length);
100+
Assert.Fail("didn't throw");
101+
} catch(InvalidStatusException e) {
102+
Assert.AreEqual(ResponseStatus.Draining, e.Status);
103+
return;
104+
} catch(Exception e) {
105+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
106+
}
107+
}
108+
109+
[Test]
110+
public void Bad_format_response_throws() {
111+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "BAD_FORMAT\r\n");
112+
var data = "foo".AsStream();
113+
try {
114+
_client.Put(0, TimeSpan.Zero, TimeSpan.Zero, data, data.Length);
115+
Assert.Fail("didn't throw");
116+
} catch(InvalidStatusException e) {
117+
Assert.AreEqual(ResponseStatus.BadFormat, e.Status);
118+
return;
119+
} catch(Exception e) {
120+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
121+
}
122+
}
123+
124+
[Test]
125+
public void Unknown_command_response_throws() {
126+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "UNKNOWN_COMMAND\r\n");
127+
var data = "foo".AsStream();
128+
try {
129+
_client.Put(0, TimeSpan.Zero, TimeSpan.Zero, data, data.Length);
130+
Assert.Fail("didn't throw");
131+
} catch(InvalidStatusException e) {
132+
Assert.AreEqual(ResponseStatus.UnknownCommand, e.Status);
133+
return;
134+
} catch(Exception e) {
135+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
136+
}
137+
}
138+
43139
[Test]
44140
public void Can_put_data() {
45141
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "INSERTED 456\r\n");
@@ -60,6 +156,36 @@ public void Can_put_data_buried() {
60156
Assert.IsTrue(response.Buried);
61157
}
62158

159+
[Test]
160+
public void Put_throws_on_too_much_data() {
161+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "JOB_TOO_BIG\r\n");
162+
var data = "foo".AsStream();
163+
try {
164+
_client.Put(123, TimeSpan.Zero, TimeSpan.FromSeconds(60), data, data.Length);
165+
Assert.Fail("didn't throw");
166+
} catch(PutFailedException e) {
167+
Assert.AreEqual(ResponseStatus.JobTooBig, e.Status);
168+
return;
169+
} catch(Exception e) {
170+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
171+
}
172+
}
173+
174+
[Test]
175+
public void Put_throws_on_expected_crlf() {
176+
_mockSocket.Expect("put 123 0 60 3\r\nfoo\r\n", "EXPECTED_CRLF\r\n");
177+
var data = "foo".AsStream();
178+
try {
179+
_client.Put(123, TimeSpan.Zero, TimeSpan.FromSeconds(60), data, data.Length);
180+
Assert.Fail("didn't throw");
181+
} catch(PutFailedException e) {
182+
Assert.AreEqual(ResponseStatus.ExpectedCrlf, e.Status);
183+
return;
184+
} catch(Exception e) {
185+
Assert.Fail(string.Format("threw '{0}' instead of InvalidStatusException", e));
186+
}
187+
}
188+
63189
[Test]
64190
public void Can_set_tube() {
65191
_mockSocket.Expect("use bob\r\n", "USING bob\r\n");
@@ -143,7 +269,7 @@ public void Can_TryReserve_with_timeout_timing_out() {
143269
}
144270

145271
[Test]
146-
public void Can_TryReserve_with_timeout_throwing_deadline_soon() {
272+
public void Can_TryReserve_with_timeout_returning_deadline_soon() {
147273
_mockSocket.Expect("reserve-with-timeout 10\r\n", "DEADLINE_SOON\r\n");
148274
Job job;
149275
Assert.AreEqual(ReservationStatus.DeadlineSoon, _client.TryReserve(TimeSpan.FromSeconds(10), out job));
@@ -305,5 +431,63 @@ public void Can_PeekBuried_not_found() {
305431
_mockSocket.Verify();
306432
}
307433

434+
[Test]
435+
public void Can_Kick() {
436+
_mockSocket.Expect("kick 10\r\n", "KICKED 5\r\n");
437+
var kicked = _client.Kick(10);
438+
_mockSocket.Verify();
439+
Assert.AreEqual(5, kicked);
440+
}
441+
442+
[Test]
443+
public void Can_get_job_stats() {
444+
_mockSocket.Expect("stats-job 10\r\n", "OK 21\r\n---\r\nid: 10\r\nfoo: bar\r\n");
445+
var jobStats = _client.GetJobStats(10);
446+
_mockSocket.Verify();
447+
Assert.AreEqual("10", jobStats["id"]);
448+
Assert.AreEqual("bar", jobStats["foo"]);
449+
}
450+
451+
[Test]
452+
public void Can_get_job_stats_not_found() {
453+
_mockSocket.Expect("stats-job 10\r\n", "NOT_FOUND\r\n");
454+
var jobStats = _client.GetJobStats(10);
455+
_mockSocket.Verify();
456+
Assert.IsNull(jobStats);
457+
}
458+
459+
[Test]
460+
public void Can_get_tube_stats() {
461+
_mockSocket.Expect("stats-tube bob\r\n", "OK 24\r\n---\r\nname: bob\r\nfoo: bar\r\n");
462+
var tubeStats = _client.GetTubeStats("bob");
463+
_mockSocket.Verify();
464+
Assert.AreEqual("bob", tubeStats["name"]);
465+
Assert.AreEqual("bar", tubeStats["foo"]);
466+
}
467+
468+
[Test]
469+
public void Can_get_tube_stats_not_found() {
470+
_mockSocket.Expect("stats-tube bob\r\n", "NOT_FOUND\r\n");
471+
var tubeStats = _client.GetTubeStats("bob");
472+
_mockSocket.Verify();
473+
Assert.IsNull(tubeStats);
474+
}
475+
476+
[Test]
477+
public void Can_get_server_stats() {
478+
_mockSocket.Expect("stats\r\n", "OK 24\r\n---\r\nname: bob\r\nfoo: bar\r\n");
479+
var serverStats = _client.GetServerStats();
480+
_mockSocket.Verify();
481+
Assert.AreEqual("bob", serverStats["name"]);
482+
Assert.AreEqual("bar", serverStats["foo"]);
483+
}
484+
485+
[Test]
486+
public void Can_list_tubes() {
487+
_mockSocket.Expect("list-tubes\r\n", "OK 23\r\n---\r\n- default\r\n- other\r\n");
488+
var tubes = _client.GetTubes();
489+
_mockSocket.Verify();
490+
Assert.AreEqual(new[]{"default","other"},tubes.OrderBy(x =>x).ToArray());
491+
}
308492
}
309493
}

Beanstalk.Client/BeanstalkClient.cs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ public BeanstalkClient(ISocket socket) {
6161
}
6262

6363
public IWatchedTubeCollection WatchedTubes { get { return _watchedTubes; } }
64-
public bool IsDisposed { get { return CheckConnection(); } }
64+
65+
public bool IsDisposed {
66+
get {
67+
IsConnected();
68+
return _isDisposed;
69+
}
70+
}
6571

6672
public string CurrentTube {
6773
get {
@@ -180,20 +186,21 @@ public Job PeekBuried() {
180186
}
181187

182188
public uint Kick(uint bound) {
183-
var response = Exec(Request.Create(RequestCommand.Touch)
189+
var response = Exec(Request.Create(RequestCommand.Kick)
184190
.AppendArgument(bound)
185191
.ExpectStatuses(ResponseStatus.Kicked));
186192
return uint.Parse(response.Arguments[0]);
187193
}
188194

189195
public JobStats GetJobStats(uint jobId) {
190-
var response = Exec(Request.Create(RequestCommand.StatsJob).ExpectStatuses(ResponseStatus.Ok));
191-
return new JobStats(MicroYaml.ParseDictionary(response));
196+
var response = Exec(Request.Create(RequestCommand.StatsJob).AppendArgument(jobId).ExpectStatuses(ResponseStatus.Ok | ResponseStatus.NotFound));
197+
return response.Status == ResponseStatus.Ok ? new JobStats(MicroYaml.ParseDictionary(response)) : null;
192198
}
193199

194200
public TubeStats GetTubeStats(string tube) {
195-
var response = Exec(Request.Create(RequestCommand.StatsTube).ExpectStatuses(ResponseStatus.Ok));
196-
return new TubeStats(MicroYaml.ParseDictionary(response));
201+
var response = Exec(Request.Create(RequestCommand.StatsTube).AppendArgument(tube).ExpectStatuses(ResponseStatus.Ok | ResponseStatus.NotFound));
202+
203+
return response.Status == ResponseStatus.Ok ? new TubeStats(MicroYaml.ParseDictionary(response)) : null;
197204
}
198205

199206
public ServerStats GetServerStats() {
@@ -240,7 +247,7 @@ private Response Exec(Request request) {
240247

241248
private void VerifyConnection() {
242249
ThrowIfDisposed();
243-
if(CheckConnection()) {
250+
if(IsConnected()) {
244251
return;
245252
}
246253
ThrowIfDisposed();
@@ -252,7 +259,7 @@ private void ThrowIfDisposed() {
252259
}
253260
}
254261

255-
private bool CheckConnection() {
262+
private bool IsConnected() {
256263
if(!_socket.Connected) {
257264
_isDisposed = true;
258265
}

Beanstalk.Client/Protocol/ResponseStatus.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,27 @@ namespace Droog.Beanstalk.Client.Protocol {
2323

2424
[Flags]
2525
public enum ResponseStatus {
26-
BadFormat,
27-
Buried,
28-
DeadlineSoon,
29-
Deleted,
30-
Draining,
31-
ExpectedCrlf,
32-
Found,
33-
Inserted,
34-
InternalError,
35-
JobTooBig,
36-
Kicked,
37-
NotFound,
38-
NotIgnored,
39-
Ok,
40-
OutOfMemory,
41-
Released,
42-
Reserved,
43-
TimedOut,
44-
Touched,
45-
UnknownCommand,
46-
Using,
47-
Watching,
26+
BadFormat = 0x1,
27+
Buried = 0x2,
28+
DeadlineSoon = 0x4,
29+
Deleted = 0x8,
30+
Draining = 0x10,
31+
ExpectedCrlf = 0x20,
32+
Found = 0x40,
33+
Inserted = 0x80,
34+
InternalError = 0x100,
35+
JobTooBig = 0x200,
36+
Kicked = 0x400,
37+
NotFound = 0x800,
38+
NotIgnored = 0x1000,
39+
Ok = 0x2000,
40+
OutOfMemory = 0x4000,
41+
Released = 0x8000,
42+
Reserved = 0x10000,
43+
TimedOut = 0x20000,
44+
Touched = 0x40000,
45+
UnknownCommand = 0x80000,
46+
Using = 0x100000,
47+
Watching = 0x200000,
4848
}
4949
}

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
libBeanstalk.NET 0.1
1+
libBeanstalk.NET 0.5
22
==========
33
A .NET driver for Beanstalkd.
44

@@ -47,7 +47,7 @@ Binary payload
4747

4848
Patches
4949
=======
50-
Patches are welcome and will likely be accepted. By submitting a patch you assign the copyright to me, Arne F. Claassen. This is necessary to simplify the number of copyright holders should it become necessary that the copyright need to be re-assigned or the code re-licensed. The code will always be available under an OSI approved license.
50+
Patches are welcome and will likely be accepted. By submitting a patch you assign the copyright to me, Arne F. Claassen. This is necessary to simplify the number of copyright holders should it become necessary that the copyright be re-assigned or the code re-licensed. The code will always be available under an OSI approved license.
5151

5252
Roadmap
5353
=======

0 commit comments

Comments
 (0)