rstyx 0.2.0 → 0.3.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.
- data/COPYING +482 -0
- data/ChangeLog +4 -0
- data/Manifest.txt +17 -0
- data/NEWS +2 -0
- data/README +41 -0
- data/Rakefile +55 -0
- data/examples/readstyxfile.rb +48 -0
- data/lib/rstyx/authmodules.rb +90 -0
- data/lib/rstyx/client.rb +709 -693
- data/lib/rstyx/common.rb +71 -0
- data/lib/rstyx/errors.rb +35 -2
- data/lib/rstyx/messages.rb +377 -1113
- data/lib/rstyx/server.rb +1305 -0
- data/lib/rstyx/version.rb +2 -2
- data/lib/rstyx.rb +11 -4
- data/tests/tc_client.rb +260 -45
- data/tests/tc_message.rb +245 -388
- data/tests/tc_styxservproto.rb +596 -0
- metadata +51 -26
data/lib/rstyx/version.rb
CHANGED
@@ -20,14 +20,14 @@
|
|
20
20
|
#
|
21
21
|
# RStyx version code
|
22
22
|
#
|
23
|
-
# $Id: version.rb
|
23
|
+
# $Id: version.rb 232 2007-08-10 08:44:34Z dido $
|
24
24
|
#
|
25
25
|
|
26
26
|
module RStyx
|
27
27
|
module Version
|
28
28
|
|
29
29
|
MAJOR = 0
|
30
|
-
MINOR =
|
30
|
+
MINOR = 3
|
31
31
|
TINY = 0
|
32
32
|
|
33
33
|
# The version of RStyx in use.
|
data/lib/rstyx.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
#
|
3
|
-
# Copyright (C) 2005 Rafael Sevilla
|
3
|
+
# Copyright (C) 2005,2006 Rafael Sevilla
|
4
4
|
# This file is part of RStyx
|
5
5
|
#
|
6
6
|
# RStyx is free software; you can redistribute it and/or modify
|
@@ -15,9 +15,16 @@
|
|
15
15
|
#
|
16
16
|
# You should have received a copy of the GNU Lesser General Public
|
17
17
|
# License along with RStyx; if not, write to the Free Software
|
18
|
-
# Foundation, Inc.,
|
19
|
-
#
|
18
|
+
# Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA.
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# Main require -- should get everything ready for the user of the lib.
|
22
22
|
#
|
23
|
+
# $Id: rstyx.rb 184 2007-06-01 08:33:49Z dido $
|
24
|
+
#
|
25
|
+
require 'rstyx/common'
|
26
|
+
require 'rstyx/messages'
|
27
|
+
require 'rstyx/errors'
|
23
28
|
require 'rstyx/client'
|
29
|
+
require 'rstyx/authmodules'
|
30
|
+
|
data/tests/tc_client.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
#
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) 2006, 2007 Rafael Sevilla
|
4
4
|
# This file is part of RStyx
|
5
5
|
#
|
6
6
|
# RStyx is free software; you can redistribute it and/or modify
|
@@ -15,60 +15,275 @@
|
|
15
15
|
#
|
16
16
|
# You should have received a copy of the GNU Lesser General Public
|
17
17
|
# License along with RStyx; if not, write to the Free Software
|
18
|
-
# Foundation, Inc.,
|
19
|
-
#
|
18
|
+
# Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
|
19
|
+
# 02110-1301 USA.
|
20
20
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# To use these tests, redefine CONNECT_HOST and CONNECT_PORT to point to
|
24
|
-
# a Styx server that will accept connections with no authentication and
|
25
|
-
# will allow write access. I'm currently using 4th Edition Inferno hosted
|
26
|
-
# on GNU/Linux to do this
|
27
|
-
#
|
28
|
-
# $Id: tc_client.rb,v 1.2 2005/11/01 13:17:04 dido Exp $
|
21
|
+
# $Id: tc_client.rb 181 2007-06-01 06:24:37Z dido $
|
29
22
|
#
|
30
23
|
require 'test/unit'
|
24
|
+
require 'flexmock'
|
31
25
|
require 'rstyx'
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
27
|
+
Thread.abort_on_exception = true
|
28
|
+
|
29
|
+
class StyxClientTester
|
30
|
+
include RStyx::Client::StyxClient
|
31
|
+
attr_reader :stopcount
|
32
|
+
|
33
|
+
def initialize(mockobj=nil)
|
34
|
+
@mockobj = mockobj
|
35
|
+
self.post_init
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delegate to the mock object other methods
|
39
|
+
def method_missing(sym, *args)
|
40
|
+
@mockobj.send(sym, *args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# fake stub for EventMachine
|
45
|
+
module EventMachine
|
46
|
+
# Phony event loop
|
47
|
+
def EventMachine.run
|
48
|
+
end
|
49
|
+
|
50
|
+
# Stop the phony event loop if it is in use
|
51
|
+
def EventMachine.stop_event_loop
|
52
|
+
@@stopcount ||= 0
|
53
|
+
@@stopcount += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def EventMachine.stopcount
|
57
|
+
return(@@stopcount)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set the mock object for the fake event machine
|
61
|
+
def EventMachine.mockobj=(m)
|
62
|
+
@mockobj = m
|
63
|
+
end
|
64
|
+
|
65
|
+
# This returns a StyxClientTester instance with the mock object
|
66
|
+
def EventMachine.connect(host, port, c)
|
67
|
+
return(StyxClientTester.new(@mockobj))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module RStyx
|
72
|
+
# redefine for testing
|
73
|
+
MAX_FID = 0xff
|
74
|
+
# DEBUG = true
|
75
|
+
end
|
76
|
+
|
77
|
+
class StyxClientTest < Test::Unit::TestCase
|
78
|
+
# Test message sending, successful cases.
|
79
|
+
def test_send_message
|
80
|
+
FlexMock.use("mock") do |mock|
|
81
|
+
q = Queue.new
|
82
|
+
mock.should_receive(:send_data).with(String).returns do |data|
|
83
|
+
m = RStyx::Message::StyxMessage.from_bytes(data)
|
84
|
+
# Send an extra Rversion with a different tag number--this
|
85
|
+
# should # be ignored. We make the message size and version
|
86
|
+
# different in this case.
|
87
|
+
rv = RStyx::Message::Rversion.new(:msize => 0x12345678,
|
88
|
+
:version => "FooBar")
|
89
|
+
rv.tag = m.tag + 1
|
90
|
+
q << rv
|
91
|
+
# Prepared response message
|
92
|
+
rv = RStyx::Message::Rversion.new(:msize => 0xdeadbeef,
|
93
|
+
:version => "9P2000")
|
94
|
+
# make their tags the same, as this is the response
|
95
|
+
rv.tag = m.tag
|
96
|
+
q << rv
|
97
|
+
end
|
98
|
+
c = StyxClientTester.new(mock)
|
99
|
+
Thread.new do
|
100
|
+
# Send the test tversion message
|
101
|
+
msg =
|
102
|
+
c.send_message(RStyx::Message::Tversion.new(:msize => 0xdeadbeef,
|
103
|
+
:version => "9P2000"))
|
104
|
+
assert_equal(RStyx::Message::Rversion, msg.class)
|
105
|
+
assert_equal(0xdeadbeef, msg.msize)
|
106
|
+
assert_equal("9P2000", msg.version)
|
107
|
+
end
|
108
|
+
data = q.shift.to_bytes
|
109
|
+
data << q.shift.to_bytes
|
110
|
+
c.receive_data(data)
|
111
|
+
end
|
112
|
+
|
113
|
+
FlexMock.use("mock") do |mock|
|
114
|
+
q = Queue.new
|
115
|
+
# Try sending the received data in pieces, see if things still work
|
116
|
+
mock.should_receive(:send_data).with(String).returns do |data|
|
117
|
+
m = RStyx::Message::StyxMessage.from_bytes(data)
|
118
|
+
# Prepared response message
|
119
|
+
rv = RStyx::Message::Rversion.new(:msize => 0xdeadbeef,
|
120
|
+
:version => "9P2000")
|
121
|
+
# make their tags the same, as this is the response
|
122
|
+
rv.tag = m.tag
|
123
|
+
q << rv
|
124
|
+
end
|
125
|
+
c = StyxClientTester.new(mock)
|
126
|
+
Thread.new do
|
127
|
+
# Send the test tversion message
|
128
|
+
msg =
|
129
|
+
c.send_message(RStyx::Message::Tversion.new(:msize => 0xdeadbeef,
|
130
|
+
:version => "9P2000"))
|
131
|
+
assert_equal(RStyx::Message::Rversion, msg.class)
|
132
|
+
assert_equal(0xdeadbeef, msg.msize)
|
133
|
+
assert_equal("9P2000", msg.version)
|
134
|
+
end
|
135
|
+
# one byte at a time
|
136
|
+
smsg = q.shift.to_bytes
|
137
|
+
smsg.each_byte do |b|
|
138
|
+
c.receive_data(b.chr)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Test receiving error cases
|
144
|
+
def test_error_cases
|
145
|
+
FlexMock.use("mock") do |mock|
|
146
|
+
q = Queue.new
|
147
|
+
mock.should_receive(:send_data).with(String).returns do |data|
|
148
|
+
m = RStyx::Message::StyxMessage.from_bytes(data)
|
149
|
+
# Prepared response message
|
150
|
+
rv = RStyx::Message::Rerror.new(:ename => "test error")
|
151
|
+
# make their tags the same, as this is the response
|
152
|
+
rv.tag = m.tag
|
153
|
+
q << rv
|
154
|
+
end
|
155
|
+
c = StyxClientTester.new(mock)
|
156
|
+
Thread.new do
|
157
|
+
# Send the test tversion message
|
158
|
+
begin
|
159
|
+
msg = c.send_message(RStyx::Message::Tversion.new(:msize => 0xdeadbeef,
|
160
|
+
:version => "9P2000"))
|
161
|
+
rescue RStyx::StyxException => e
|
162
|
+
assert_equal("test error", e.message)
|
163
|
+
rescue Exception => e
|
164
|
+
flunk("exception of unexpected type #{e.class.to_s} received")
|
165
|
+
else
|
166
|
+
flunk("no exception received where expected")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
c.receive_data(q.shift.to_bytes)
|
170
|
+
end
|
171
|
+
|
172
|
+
FlexMock.use("mock") do |mock|
|
173
|
+
q = Queue.new
|
174
|
+
# Try sending a reply different from what was expected. Typical
|
175
|
+
# case of this sort that would appear in practice might be if
|
176
|
+
# a message gets flushed.
|
177
|
+
mock.should_receive(:send_data).with(String).returns do |data|
|
178
|
+
m = RStyx::Message::StyxMessage.from_bytes(data)
|
179
|
+
# Prepared response message
|
180
|
+
rv = RStyx::Message::Rflush.new
|
181
|
+
# make their tags the same, as this is the response
|
182
|
+
rv.tag = m.tag
|
183
|
+
q << rv
|
184
|
+
end
|
185
|
+
c = StyxClientTester.new(mock)
|
186
|
+
Thread.new do
|
187
|
+
# Send the test tversion message
|
188
|
+
begin
|
189
|
+
msg = c.send_message(RStyx::Message::Tversion.new(:msize => 0xdeadbeef,
|
190
|
+
:version => "9P2000"))
|
191
|
+
rescue RStyx::StyxException => e
|
192
|
+
assert_match(/^Unexpected.*received in response to/, e.message)
|
193
|
+
rescue Exception => e
|
194
|
+
flunk("exception of unexpected type #{e.class.to_s} received")
|
195
|
+
else
|
196
|
+
flunk("no exception received where expected")
|
197
|
+
end
|
198
|
+
end
|
199
|
+
c.receive_data(q.shift.to_bytes)
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
# Test disconnect
|
206
|
+
def test_disconnect
|
207
|
+
# Here be dragons... We're attempting to synchronize the behavior
|
208
|
+
# of several threads.
|
209
|
+
FlexMock.use("mock") do |mock|
|
210
|
+
EventMachine.mockobj=mock
|
211
|
+
mock.should_receive(:stop_event_loop)
|
212
|
+
c = StyxClientTester.new(mock)
|
213
|
+
flush_count = 0
|
214
|
+
|
215
|
+
mock.should_receive(:send_data).with(String).returns do |data|
|
216
|
+
m = RStyx::Message::StyxMessage.from_bytes(data)
|
217
|
+
# Respond only to Tflush messages, no response to other
|
218
|
+
# messages sent.
|
219
|
+
if m.class == RStyx::Message::Tflush
|
220
|
+
flush_count += 1
|
221
|
+
rv = RStyx::Message::Rflush.new(:tag => m.tag)
|
222
|
+
c.receive_data(rv.to_bytes)
|
54
223
|
end
|
224
|
+
end
|
55
225
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
226
|
+
q = Queue.new
|
227
|
+
# This thread waits for something to appear in the
|
228
|
+
# queue, sent by the send_message_async below, before
|
229
|
+
# sending the disconnect
|
230
|
+
Thread.new do
|
231
|
+
q.shift
|
232
|
+
c.disconnect
|
233
|
+
# Test postconditions
|
234
|
+
assert_equal(10, flush_count)
|
235
|
+
assert_equal(1, EventMachine.stopcount)
|
236
|
+
end
|
237
|
+
|
238
|
+
# This thread sends several Tversion messages, and expects them to
|
239
|
+
# all be flushed, i.e. each send_message_async should receive
|
240
|
+
# an Rflush message as the response.
|
241
|
+
Thread.new do
|
242
|
+
1.upto(10) do
|
243
|
+
c.send_message_async(RStyx::Message::Tversion.new(:msize => 0xdeadbeef,
|
244
|
+
:version => "9P2000")) do |tx, rx|
|
245
|
+
# We should be expecting rx to be an Rflush message
|
246
|
+
assert_equal(RStyx::Message::Rflush, rx.class)
|
62
247
|
end
|
63
248
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
assert_nothing_raised { c.rmdir("/rstyx_test_dir") }
|
69
|
-
# Deleting the directory twice should generate an error
|
70
|
-
assert_raise(RStyx::StyxException) { c.rmdir(TEST_DIRECTORY) }
|
249
|
+
|
250
|
+
# Wake up the thread waiting on the queue above, now that the
|
251
|
+
# message is out.
|
252
|
+
q << 0
|
71
253
|
end
|
72
254
|
end
|
73
255
|
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# Test the connection class
|
261
|
+
#
|
262
|
+
class ConnectionTest < Test::Unit::TestCase
|
263
|
+
# Test the fid get/return methods
|
264
|
+
def test_fid_methods
|
265
|
+
c = RStyx::Client::Connection.new
|
266
|
+
fid = c.send(:get_free_fid)
|
267
|
+
assert(c.usedfids.include?(fid))
|
268
|
+
c.send(:return_fid, fid)
|
269
|
+
assert(!c.usedfids.include?(fid))
|
270
|
+
|
271
|
+
# Get all fids, and test for the error condition of running
|
272
|
+
# out of fids.
|
273
|
+
0.upto(RStyx::MAX_FID) do |i|
|
274
|
+
c.send(:get_free_fid)
|
275
|
+
end
|
276
|
+
assert_raises(RStyx::StyxException) do
|
277
|
+
c.send(:get_free_fid)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_connect
|
282
|
+
# Just raises an exception--as this class shouldn't be used
|
283
|
+
# as is.
|
284
|
+
c = RStyx::Client::Connection.new
|
285
|
+
assert_raises(RStyx::StyxException) do
|
286
|
+
c.connect
|
287
|
+
end
|
288
|
+
end
|
74
289
|
end
|