fake_ftp 0.1.0 → 0.1.1

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.
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
+