fake_ftp 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef1324d66ffeb222bc35a3d1fe172bf649fefa9e
4
- data.tar.gz: 285616254bf9b2f5ad441bfc41d17943a1609681
3
+ metadata.gz: 50a4678ec926f8b3ac68aa2db5670987c7c19558
4
+ data.tar.gz: caf6eef42de1e306f19860b56265b8e64ced3040
5
5
  SHA512:
6
- metadata.gz: b20a024c9e598db59fac9751517b08cc70c5325f0ba55b96352d719a0227827a18a956ef2e30e85f9c544009c4214f7285bf3d69a0139e66bdd3e0bed207c711
7
- data.tar.gz: ecd74f559bf7d48318846671268c5b3d96468c93a3ad6fff487f310014b47e413244e55f700e8881c54565c4dd066d2d0c0573322aba70eb57d75d33f3dc1d16
6
+ metadata.gz: 70a2926c93a0aff84dc95d52ea0312809bac104dd5d885eeac968932c5b82336d98115d0770ff20db0ad58efce8df62c55bc55376c2991bd9db12ff7680b4018
7
+ data.tar.gz: d7b0cd6eb3d31c651aab69cca842bbb6f6da82e7487184e2dea56d75c4aa80e5cb641e31146776873ad0d1b574e0c0960ed84750755dcd8e68f172439aea623d
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.0.0
4
+ - 1.9.3
3
5
  - 1.8.7
4
- gemfile:
5
- - Gemfile.travis
data/CONTRIBUTORS.md ADDED
@@ -0,0 +1,19 @@
1
+ Contributors
2
+ ============
3
+
4
+ * Eric Saxby - @sax
5
+
6
+ * Ben Ashford
7
+ * Colin Shield
8
+ * Eirik Lied
9
+ * Eric Oestrich
10
+ * Jacob Maine
11
+ * John Maxwell
12
+ * Kevin Thompson
13
+ * liehann
14
+ * mdalton
15
+ * Nick Rowe
16
+ * Pranas Kiziela
17
+ * Puneet Goyal
18
+ * Steve Thompson
19
+ * Thomas Sonntag
@@ -3,17 +3,23 @@ FakeFtp
3
3
 
4
4
  [![Build status](https://secure.travis-ci.org/livinginthepast/fake_ftp.png)](http://travis-ci.org/livinginthepast/fake_ftp)
5
5
 
6
- This is a gem that allows you to test FTP implementations in ruby. It is a minimal single-client FTP server
7
- that can be bound to any arbitrary port on localhost.
6
+ This is a gem that allows you to test FTP implementations in ruby. It is
7
+ a minimal single-client FTP server that can be bound to any arbitrary
8
+ port on localhost.
9
+
8
10
 
9
11
  ## Why?
10
12
 
11
- We want to ensure that our code works, in a way that is agnostic to the implementation used (unlike with stubs or mocks).
13
+ We want to ensure that our code works, in a way that is agnostic to the
14
+ implementation used (unlike with stubs or mocks).
15
+
12
16
 
13
17
  ## How
14
18
 
15
- FakeFtp is a simple FTP server that fakes out enough of the protocol to get us by, allowing us to test that files get to
16
- their intended destination rather than testing how our code does so.
19
+ FakeFtp is a simple FTP server that fakes out enough of the protocol to
20
+ get us by, allowing us to test that files get to their intended destination
21
+ rather than testing how our code does so.
22
+
17
23
 
18
24
  ## Usage
19
25
 
@@ -66,17 +72,43 @@ server.stop
66
72
 
67
73
  Note that many FTP clients default to active, unless specified otherwise.
68
74
 
75
+
76
+ ## Caveats
77
+
78
+ This is *not* a real FTP server and should not be treated as one. The goal
79
+ of this gem is not to create a thread-safe multi-client implementation.
80
+ It is best used to unit test models that generate files and transfer
81
+ them to an FTP server.
82
+
83
+ As such, there are some things that won't be accepted upstream from pull
84
+ requests:
85
+ * simultaneous multi-client code
86
+ * support for long term file persistence
87
+ * binding to arbitrary IPs
88
+ * global state beyond that required to pass the minimum required to
89
+ generate passing tests
90
+
91
+
92
+ ## Recommendations for testing patterns
93
+
94
+ *Separate configuration from code.* Do not hard code the IP address,
95
+ FQDN or port of an FTP server in your classes. It introduces fragility
96
+ into your tests. Also, the default FTP port of 21 is a privileged port,
97
+ and should be avoided.
98
+
99
+ *Separate the code that generates files from the code that uploads
100
+ files.* You tests will run much more quickly if you only try to upload
101
+ small files. If you have tests showing that you generate correct files
102
+ from your data, then you can trust that. Why do you need to upload a 20M
103
+ file in your tests if you can stub out your file generation method and
104
+ test file upload against 10 bytes? Fast fast fast.
105
+
106
+
69
107
  ## References
70
108
 
71
109
  * http://rubyforge.org/projects/ftpd/ - a simple ftp daemon written by Chris Wanstrath
72
110
  * http://ruby-doc.org/stdlib/libdoc/gserver/rdoc/index.html - a generic server in the Ruby standard library, by John W Small
73
111
 
74
- ## Contributors
75
-
76
- * Eric Saxby
77
- * Colin Shield
78
- * liehann (https://github.com/liehann)
79
-
80
112
  ## License
81
113
 
82
114
  The MIT License
data/fake_ftp.gemspec CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "http://rubygems.org/gems/fake_ftp"
12
12
  s.summary = %q{Creates a fake FTP server for use in testing}
13
13
  s.description = %q{Testing FTP? Use this!}
14
+ s.license = 'MIT'
14
15
 
15
16
  s.required_rubygems_version = ">= 1.3.6"
16
17
 
@@ -34,8 +34,8 @@ module FakeFtp
34
34
  def initialize(control_port = 21, data_port = nil, options = {})
35
35
  self.port = control_port
36
36
  self.passive_port = data_port
37
- raise(Errno::EADDRINUSE, "#{port}") if is_running?
38
- raise(Errno::EADDRINUSE, "#{passive_port}") if passive_port && is_running?(passive_port)
37
+ raise(Errno::EADDRINUSE, "#{port}") if !control_port.zero? && is_running?
38
+ raise(Errno::EADDRINUSE, "#{passive_port}") if passive_port && !passive_port.zero? && is_running?(passive_port)
39
39
  @connection = nil
40
40
  @options = options
41
41
  @files = []
@@ -62,6 +62,7 @@ module FakeFtp
62
62
  def start
63
63
  @started = true
64
64
  @server = ::TCPServer.new('127.0.0.1', port)
65
+ @port = @server.addr[1]
65
66
  @thread = Thread.new do
66
67
  while @started
67
68
  @client = @server.accept rescue nil
@@ -87,6 +88,7 @@ module FakeFtp
87
88
 
88
89
  if passive_port
89
90
  @data_server = ::TCPServer.new('127.0.0.1', passive_port)
91
+ @passive_port = @data_server.addr[1]
90
92
  end
91
93
  end
92
94
 
@@ -162,9 +164,9 @@ module FakeFtp
162
164
  end
163
165
  end
164
166
  files = files.map do |f|
165
- "-rw-r--r--\t1\towner\tgroup\t#{f.bytes}\t#{f.created.strftime('%b %d %H:%M')}\t#{f.name}"
167
+ "-rw-r--r--\t1\towner\tgroup\t#{f.bytes}\t#{f.created.strftime('%b %d %H:%M')}\t#{f.name}\n"
166
168
  end
167
- data_client.write(files.join("\n"))
169
+ data_client.write(files.join)
168
170
  data_client.close
169
171
  @active_connection = nil
170
172
 
@@ -1,3 +1,3 @@
1
1
  module FakeFtp
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,468 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe FakeFtp::Server, 'commands' do
4
+ let(:server) { FakeFtp::Server.new(21212, 21213) }
5
+ let(:client) { TCPSocket.open('127.0.0.1', 21212) }
6
+
7
+ before { server.start }
8
+
9
+ after {
10
+ client.close
11
+ server.stop
12
+ }
13
+
14
+ context 'general' do
15
+ it "should accept connections" do
16
+ expect(client.gets).to eql("220 Can has FTP?\r\n")
17
+ end
18
+
19
+ it "should get unknown command response when nothing is sent" do
20
+ client.gets
21
+ client.puts
22
+ expect(client.gets).to eql("500 Unknown command\r\n")
23
+ end
24
+
25
+ it "accepts QUIT" do
26
+ client.gets
27
+ client.puts "QUIT"
28
+ expect(client.gets).to eql("221 OMG bye!\r\n")
29
+ end
30
+
31
+ it "should accept multiple commands in one session" do
32
+ client.gets
33
+ client.puts "USER thing"
34
+ client.gets
35
+ client.puts "PASS thing"
36
+ client.gets
37
+ client.puts "ACCT thing"
38
+ client.gets
39
+ client.puts "USER thing"
40
+ end
41
+ end
42
+
43
+ context 'passive' do
44
+ it "accepts PASV" do
45
+ expect(server.mode).to eql(:active)
46
+ client.gets
47
+ client.puts "PASV"
48
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,221)\r\n")
49
+ expect(server.mode).to eql(:passive)
50
+ end
51
+
52
+ it "responds with correct PASV port" do
53
+ server.stop
54
+ server.passive_port = 21111
55
+ server.start
56
+ client.gets
57
+ client.puts "PASV"
58
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,119)\r\n")
59
+ end
60
+
61
+ it "does not accept PASV if no port set" do
62
+ server.stop
63
+ server.passive_port = nil
64
+ server.start
65
+ client.gets
66
+ client.puts "PASV"
67
+ expect(client.gets).to eql("502 Aww hell no, use Active\r\n")
68
+ end
69
+ end
70
+
71
+ context 'active' do
72
+ let!(:data_server) { ::TCPServer.new('127.0.0.1', 21216) }
73
+
74
+ before :each do
75
+ client.gets
76
+
77
+ @data_connection = Thread.new do
78
+ @server_client = data_server.accept
79
+ expect(@server_client).to_not be_nil
80
+ end
81
+ end
82
+
83
+ after :each do
84
+ data_server.close
85
+ end
86
+
87
+ it "accepts PORT and connects to port" do
88
+ client.puts "PORT 127,0,0,1,82,224"
89
+ expect(client.gets).to eql("200 Okay\r\n")
90
+
91
+ @data_connection.join
92
+ end
93
+
94
+ it "should switch to :active on port command" do
95
+ expect(server.mode).to eql(:active)
96
+ client.puts 'PASV'
97
+ client.gets
98
+ expect(server.mode).to eql(:passive)
99
+
100
+ client.puts "PORT 127,0,0,1,82,224"
101
+ expect(client.gets).to eql("200 Okay\r\n")
102
+
103
+ @data_connection.join
104
+
105
+ expect(server.mode).to eql(:active)
106
+ end
107
+ end
108
+
109
+ context 'authentication commands' do
110
+ before :each do
111
+ client.gets ## connection successful response
112
+ end
113
+
114
+ it "accepts USER" do
115
+ client.puts "USER some_dude"
116
+ expect(client.gets).to eql("331 send your password\r\n")
117
+ end
118
+
119
+ it "accepts anonymous USER" do
120
+ client.puts "USER anonymous"
121
+ expect(client.gets).to eql("230 logged in\r\n")
122
+ end
123
+
124
+ it "accepts PASS" do
125
+ client.puts "PASS password"
126
+ expect(client.gets).to eql("230 logged in\r\n")
127
+ end
128
+
129
+ it "accepts ACCT" do
130
+ client.puts "ACCT"
131
+ expect(client.gets).to eql("230 WHATEVER!\r\n")
132
+ end
133
+ end
134
+
135
+ context 'directory commands' do
136
+ before :each do
137
+ client.gets ## connection successful response
138
+ end
139
+
140
+ it "returns directory on PWD" do
141
+ client.puts "PWD"
142
+ expect(client.gets).to eql("257 \"/pub\" is current directory\r\n")
143
+ end
144
+
145
+ it "says OK to any CWD, CDUP, without doing anything" do
146
+ client.puts "CWD somewhere/else"
147
+ expect(client.gets).to eql("250 OK!\r\n")
148
+ client.puts "CDUP"
149
+ expect(client.gets).to eql("250 OK!\r\n")
150
+ end
151
+ end
152
+
153
+ context 'file commands' do
154
+ before :each do
155
+ client.gets ## connection successful response
156
+ end
157
+
158
+ it "accepts TYPE ascii" do
159
+ client.puts "TYPE A"
160
+ expect(client.gets).to eql("200 Type set to A.\r\n")
161
+ end
162
+
163
+ it "accepts TYPE image" do
164
+ client.puts "TYPE I"
165
+ expect(client.gets).to eql("200 Type set to I.\r\n")
166
+ end
167
+
168
+ it "does not accept TYPEs other than ascii or image" do
169
+ client.puts "TYPE E"
170
+ expect(client.gets).to eql("504 We don't allow those\r\n")
171
+ client.puts "TYPE N"
172
+ expect(client.gets).to eql("504 We don't allow those\r\n")
173
+ client.puts "TYPE T"
174
+ expect(client.gets).to eql("504 We don't allow those\r\n")
175
+ client.puts "TYPE C"
176
+ expect(client.gets).to eql("504 We don't allow those\r\n")
177
+ client.puts "TYPE L"
178
+ expect(client.gets).to eql("504 We don't allow those\r\n")
179
+ end
180
+
181
+ context 'passive' do
182
+ let(:data_client) { TCPSocket.open('127.0.0.1', 21213) }
183
+
184
+ before :each do
185
+ client.puts 'PASV'
186
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,221)\r\n")
187
+ end
188
+
189
+ it "accepts STOR with filename" do
190
+ client.puts "STOR some_file"
191
+ expect(client.gets).to eql("125 Do it!\r\n")
192
+ data_client.puts "1234567890"
193
+ data_client.close
194
+ expect(client.gets).to eql("226 Did it!\r\n")
195
+ expect(server.files).to include('some_file')
196
+ expect(server.file('some_file').bytes).to eql(10)
197
+ expect(server.file('some_file').data).to eql("1234567890")
198
+ end
199
+
200
+ it "accepts STOR with filename and trailing newline" do
201
+ client.puts "STOR some_file"
202
+ client.gets
203
+ # puts tries to be smart and only write a single \n
204
+ data_client.puts "1234567890\n\n"
205
+ data_client.close
206
+ expect(client.gets).to eql("226 Did it!\r\n")
207
+ expect(server.files).to include('some_file')
208
+ expect(server.file('some_file').bytes).to eql(11)
209
+ expect(server.file('some_file').data).to eql("1234567890\n")
210
+ end
211
+
212
+ it "accepts STOR with filename and long file" do
213
+ client.puts "STOR some_file"
214
+ expect(client.gets).to eql("125 Do it!\r\n")
215
+ data_client.puts("1234567890" * 10_000)
216
+ data_client.close
217
+ expect(client.gets).to eql("226 Did it!\r\n")
218
+ expect(server.files).to include('some_file')
219
+ end
220
+
221
+ it "accepts STOR with streams" do
222
+ client.puts "STOR some_file"
223
+ expect(client.gets).to eql("125 Do it!\r\n")
224
+ data_client.write "1234567890"
225
+ data_client.flush
226
+ data_client.write "1234567890"
227
+ data_client.flush
228
+ data_client.close
229
+ expect(client.gets).to eql("226 Did it!\r\n")
230
+ expect(server.file('some_file').data).to eql("12345678901234567890")
231
+ end
232
+
233
+ it "does not accept RETR without a filename" do
234
+ client.puts "RETR"
235
+ expect(client.gets).to eql("501 No filename given\r\n")
236
+ end
237
+
238
+ it "does not serve files that do not exist" do
239
+ client.puts "RETR some_file"
240
+ expect(client.gets).to eql("550 File not found\r\n")
241
+ end
242
+
243
+ it "accepts RETR with a filename" do
244
+ server.add_file('some_file', '1234567890')
245
+ client.puts "RETR some_file"
246
+ expect(client.gets).to eql("150 File status ok, about to open data connection\r\n")
247
+ data = data_client.read(1024)
248
+ data_client.close
249
+ expect(data).to eql('1234567890')
250
+ expect(client.gets).to eql("226 File transferred\r\n")
251
+ end
252
+
253
+ it "accepts DELE with a filename" do
254
+ server.add_file('some_file', '1234567890')
255
+ client.puts "DELE some_file"
256
+ expect(client.gets).to eql("250 Delete operation successful.\r\n")
257
+ expect(server.files).to_not include('some_file')
258
+ end
259
+
260
+ it "gives error message when trying to delete a file that does not exist" do
261
+ client.puts "DELE non_existing_file"
262
+ expect(client.gets).to eql("550 Delete operation failed.\r\n")
263
+ end
264
+
265
+ it "accepts a LIST command" do
266
+ server.add_file('some_file', '1234567890')
267
+ server.add_file('another_file', '1234567890')
268
+ client.puts "LIST"
269
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
270
+ data = data_client.read(2048)
271
+ data_client.close
272
+ expect(data).to eql([
273
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file('some_file').created.strftime('%b %d %H:%M')}\tsome_file\n",
274
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file('another_file').created.strftime('%b %d %H:%M')}\tanother_file\n",
275
+ ].join)
276
+ expect(client.gets).to eql("226 List information transferred\r\n")
277
+ end
278
+
279
+ it "accepts a LIST command with a wildcard argument" do
280
+ files = ['test.jpg', 'test-2.jpg', 'test.txt']
281
+ files.each do |file|
282
+ server.add_file(file, '1234567890')
283
+ end
284
+
285
+ client.puts "LIST *.jpg"
286
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
287
+
288
+ data = data_client.read(2048)
289
+ data_client.close
290
+ expect(data).to eql(files[0,2].map do |file|
291
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file(file).created.strftime('%b %d %H:%M')}\t#{file}\n"
292
+ end.join)
293
+ expect(client.gets).to eql("226 List information transferred\r\n")
294
+ end
295
+
296
+ it "accepts a LIST command with multiple wildcard arguments" do
297
+ files = ['test.jpg', 'test.gif', 'test.txt']
298
+ files.each do |file|
299
+ server.add_file(file, '1234567890')
300
+ end
301
+
302
+ client.puts "LIST *.jpg *.gif"
303
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
304
+
305
+ data = data_client.read(2048)
306
+ data_client.close
307
+ expect(data).to eql(files[0,2].map do |file|
308
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file(file).created.strftime('%b %d %H:%M')}\t#{file}\n"
309
+ end.join)
310
+ expect(client.gets).to eql("226 List information transferred\r\n")
311
+ end
312
+
313
+ it "accepts an NLST command" do
314
+ server.add_file('some_file', '1234567890')
315
+ server.add_file('another_file', '1234567890')
316
+ client.puts "NLST"
317
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
318
+ data = data_client.read(1024)
319
+ data_client.close
320
+ expect(data).to eql("some_file\nanother_file")
321
+ expect(client.gets).to eql("226 List information transferred\r\n")
322
+ end
323
+
324
+ it "should allow mdtm" do
325
+ filename = "file.txt"
326
+ now = Time.now
327
+ server.add_file(filename, "some dummy content", now)
328
+ client.puts "MDTM #{filename}"
329
+ expect(client.gets).to eql("213 #{now.strftime("%Y%m%d%H%M%S")}\r\n")
330
+ end
331
+ end
332
+
333
+ context 'active' do
334
+ let!(:data_server) { ::TCPServer.new('127.0.0.1', 21216) }
335
+
336
+ before :each do
337
+ @data_connection = Thread.new do
338
+ @server_client = data_server.accept
339
+ end
340
+ end
341
+
342
+ after :each do
343
+ data_server.close
344
+ @data_connection = nil
345
+ end
346
+
347
+ it 'creates a directory on MKD' do
348
+ client.puts "MKD some_dir"
349
+ expect(client.gets).to eql("257 OK!\r\n")
350
+ end
351
+
352
+ it 'should save the directory after you CWD' do
353
+ client.puts "CWD /somewhere/else"
354
+ expect(client.gets).to eql("250 OK!\r\n")
355
+ client.puts "PWD"
356
+ expect(client.gets).to eql("257 \"/somewhere/else\" is current directory\r\n")
357
+ end
358
+
359
+ it 'CWD should add a / to the beginning of the directory' do
360
+ client.puts "CWD somewhere/else"
361
+ expect(client.gets).to eql("250 OK!\r\n")
362
+ client.puts "PWD"
363
+ expect(client.gets).to eql("257 \"/somewhere/else\" is current directory\r\n")
364
+ end
365
+
366
+ it 'should not change the directory on CDUP' do
367
+ client.puts "CDUP"
368
+ expect(client.gets).to eql("250 OK!\r\n")
369
+ client.puts "PWD"
370
+ expect(client.gets).to eql("257 \"/pub\" is current directory\r\n")
371
+ end
372
+
373
+ it "sends error message if no PORT received" do
374
+ client.puts "STOR some_file"
375
+ expect(client.gets).to eql("425 Ain't no data port!\r\n")
376
+ end
377
+
378
+ it "accepts STOR with filename" do
379
+ client.puts "PORT 127,0,0,1,82,224"
380
+ expect(client.gets).to eql("200 Okay\r\n")
381
+
382
+ client.puts "STOR some_other_file"
383
+ expect(client.gets).to eql("125 Do it!\r\n")
384
+
385
+ @data_connection.join
386
+ @server_client.print "12345"
387
+ @server_client.close
388
+
389
+ expect(client.gets).to eql("226 Did it!\r\n")
390
+ expect(server.files).to include('some_other_file')
391
+ expect(server.file('some_other_file').bytes).to eql(5)
392
+ end
393
+
394
+ it "accepts RETR with a filename" do
395
+ client.puts "PORT 127,0,0,1,82,224"
396
+ expect(client.gets).to eql("200 Okay\r\n")
397
+
398
+ server.add_file('some_file', '1234567890')
399
+ client.puts "RETR some_file"
400
+ expect(client.gets).to eql("150 File status ok, about to open data connection\r\n")
401
+
402
+ @data_connection.join
403
+ data = @server_client.read(1024)
404
+ @server_client.close
405
+
406
+ expect(data).to eql('1234567890')
407
+ expect(client.gets).to eql("226 File transferred\r\n")
408
+ end
409
+
410
+ it "accepts RNFR without filename" do
411
+ client.puts "RNFR"
412
+ expect(client.gets).to eql("501 Send path name.\r\n")
413
+ end
414
+
415
+ it "accepts RNTO without RNFR" do
416
+ client.puts "RNTO some_other_file"
417
+ expect(client.gets).to eql("503 Send RNFR first.\r\n")
418
+ end
419
+
420
+ it "accepts RNTO and RNFR without filename" do
421
+ client.puts "RNFR from_file"
422
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
423
+
424
+ client.puts "RNTO"
425
+ expect(client.gets).to eql("501 Send path name.\r\n")
426
+ end
427
+
428
+ it "accepts RNTO and RNFR for not existing file" do
429
+ client.puts "RNFR from_file"
430
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
431
+
432
+ client.puts "RNTO to_file"
433
+ expect(client.gets).to eql("550 File not found.\r\n")
434
+ end
435
+
436
+ it "accepts RNTO and RNFR" do
437
+ server.add_file('from_file', '1234567890')
438
+
439
+ client.puts "RNFR from_file"
440
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
441
+
442
+ client.puts "RNTO to_file"
443
+ expect(client.gets).to eql("250 Path renamed.\r\n")
444
+
445
+ expect(server.files).to include('to_file')
446
+ expect(server.files).to_not include('from_file')
447
+ end
448
+
449
+ it "accepts an NLST command" do
450
+ client.puts "PORT 127,0,0,1,82,224"
451
+ expect(client.gets).to eql("200 Okay\r\n")
452
+
453
+ server.add_file('some_file', '1234567890')
454
+ server.add_file('another_file', '1234567890')
455
+ client.puts "NLST"
456
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
457
+
458
+ @data_connection.join
459
+ data = @server_client.read(1024)
460
+ @server_client.close
461
+
462
+ expect(data).to eql("some_file\nanother_file")
463
+ expect(client.gets).to eql("226 List information transferred\r\n")
464
+ end
465
+ end
466
+ end
467
+ end
468
+