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/lib/rstyx/version.rb CHANGED
@@ -20,14 +20,14 @@
20
20
  #
21
21
  # RStyx version code
22
22
  #
23
- # $Id: version.rb,v 1.2 2005/11/01 13:17:27 dido Exp $
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 = 2
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., 59 Temple Place, Suite 330, Boston, MA
19
- # 02111-1307 USA.
18
+ # Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
19
+ # 02110-1301 USA.
20
20
  #
21
- # $Id: rstyx.rb,v 1.1 2005/09/30 08:39:18 dido Exp $
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) 2005 Rafael Sevilla
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., 59 Temple Place, Suite 330, Boston, MA
19
- # 02111-1307 USA.
18
+ # Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
19
+ # 02110-1301 USA.
20
20
  #
21
- # Unit tests for Styx client.
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
- class ClientTest < Test::Unit::TestCase
34
- CONNECT_HOST = "127.0.0.1"
35
- CONNECT_PORT = "1234"
36
- TEST_DIRECTORY = "/rstyx_test_dir"
37
- TEST_FILE = TEST_DIRECTORY + "/test.file"
38
-
39
- def test_client
40
- RStyx::Client::TCPConnection.new(CONNECT_HOST, CONNECT_PORT) do |c|
41
- begin
42
- # Create the directory
43
- assert_nothing_raised { c.mkdir(TEST_DIRECTORY) }
44
- # Try to create the directory again (this should result in an error)
45
- assert_raise(RStyx::StyxException) { c.mkdir(TEST_DIRECTORY) }
46
-
47
- # open a file in the directory for writing, and fill it with data
48
- assert_nothing_raised do
49
- c.open(TEST_FILE, "w") do |fp|
50
- 0.upto(1024) do |i|
51
- fp.write(sprintf("%04x\n", i))
52
- end
53
- end
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
- # Open the file for reading, and check that the data is correct
57
- c.open(TEST_FILE, "r") do |fp|
58
- i = 0
59
- fp.each do |line|
60
- assert(line == sprintf("%04x\n", i))
61
- i += 1
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
- ensure
65
- assert_nothing_raised { c.delete(TEST_FILE) }
66
- assert_raise(RStyx::StyxException) { c.delete(TEST_FILE) }
67
- # Make sure the directories are deleted.
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