fake_ftp 0.0.2 → 0.0.3
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/README.markdown +1 -3
- data/lib/fake_ftp/server.rb +23 -14
- data/lib/fake_ftp/version.rb +1 -1
- data/spec/models/fake_ftp/server_spec.rb +111 -34
- metadata +4 -4
data/README.markdown
CHANGED
@@ -15,8 +15,6 @@ How
|
|
15
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
16
|
their intended destination rather than testing how our code does so.
|
17
17
|
|
18
|
-
Note: Only passive FTP is currently implemented
|
19
|
-
|
20
18
|
Usage
|
21
19
|
-----
|
22
20
|
|
@@ -43,7 +41,7 @@ Usage
|
|
43
41
|
TODO
|
44
42
|
----
|
45
43
|
|
46
|
-
*
|
44
|
+
* files should track if uploaded via active or passive
|
47
45
|
|
48
46
|
References
|
49
47
|
----------
|
data/lib/fake_ftp/server.rb
CHANGED
@@ -5,6 +5,7 @@ module FakeFtp
|
|
5
5
|
class Server
|
6
6
|
|
7
7
|
attr_accessor :port, :passive_port
|
8
|
+
attr_reader :mode
|
8
9
|
|
9
10
|
CMDS = %w[acct cwd cdup pass pasv port pwd quit stor type user]
|
10
11
|
LNBK = "\r\n"
|
@@ -17,6 +18,7 @@ module FakeFtp
|
|
17
18
|
@connection = nil
|
18
19
|
@options = options
|
19
20
|
@files = []
|
21
|
+
@mode = :active
|
20
22
|
end
|
21
23
|
|
22
24
|
def files
|
@@ -24,7 +26,7 @@ module FakeFtp
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def file(name)
|
27
|
-
@files.detect { |file| file.name == name}
|
29
|
+
@files.detect { |file| file.name == name }
|
28
30
|
end
|
29
31
|
|
30
32
|
def start
|
@@ -100,6 +102,7 @@ module FakeFtp
|
|
100
102
|
|
101
103
|
def _pasv(*args)
|
102
104
|
if passive_port
|
105
|
+
@mode = :passive
|
103
106
|
p1 = (passive_port / 256).to_i
|
104
107
|
p2 = passive_port % 256
|
105
108
|
"227 Entering Passive Mode (127,0,0,1,#{p1},#{p2})"
|
@@ -109,16 +112,15 @@ module FakeFtp
|
|
109
112
|
end
|
110
113
|
|
111
114
|
def _port(remote)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
'500 Not implemented yet'
|
115
|
+
remote = remote.first.split(',')
|
116
|
+
remote_port = remote[4].to_i * 256 + remote[5].to_i
|
117
|
+
unless @active_connection.nil?
|
118
|
+
@active_connection.close
|
119
|
+
@active_connection = nil
|
120
|
+
end
|
121
|
+
@mode = :active
|
122
|
+
@active_connection = ::TCPSocket.open('127.0.0.1', remote_port)
|
123
|
+
'200 Okay'
|
122
124
|
end
|
123
125
|
|
124
126
|
def _pwd(*args)
|
@@ -132,15 +134,22 @@ module FakeFtp
|
|
132
134
|
end
|
133
135
|
|
134
136
|
def _stor(filename)
|
135
|
-
|
137
|
+
if @mode == :passive
|
138
|
+
respond_with('125 Do it!')
|
139
|
+
data_client = @data_server.accept
|
140
|
+
else
|
141
|
+
respond_with('425 Ain\'t no data port!') && return if @active_connection.nil?
|
142
|
+
respond_with('125 Do it!')
|
136
143
|
|
137
|
-
|
138
|
-
|
144
|
+
data_client = @active_connection
|
145
|
+
end
|
139
146
|
|
147
|
+
data = data_client.recv(1024)
|
140
148
|
file = FakeFtp::File.new(::File.basename(filename.to_s), data.length)
|
141
149
|
@files << file
|
142
150
|
|
143
151
|
data_client.close
|
152
|
+
@active_connection = nil
|
144
153
|
'226 Did it!'
|
145
154
|
end
|
146
155
|
|
data/lib/fake_ftp/version.rb
CHANGED
@@ -33,6 +33,11 @@ describe FakeFtp::Server do
|
|
33
33
|
server.is_running?.should be_false
|
34
34
|
end
|
35
35
|
|
36
|
+
it "should default :mode to :active" do
|
37
|
+
server = FakeFtp::Server.new(21212, 21213)
|
38
|
+
server.mode.should == :active
|
39
|
+
end
|
40
|
+
|
36
41
|
it "should start and stop passive port" do
|
37
42
|
server = FakeFtp::Server.new(21212, 21213)
|
38
43
|
server.is_running?(21213).should be_false
|
@@ -128,10 +133,12 @@ describe FakeFtp::Server do
|
|
128
133
|
end
|
129
134
|
|
130
135
|
it "accepts PASV" do
|
136
|
+
@server.mode.should == :active
|
131
137
|
@client = TCPSocket.open('127.0.0.1', 21212)
|
132
138
|
@client.gets
|
133
139
|
@client.puts "PASV"
|
134
140
|
@client.gets.should == "227 Entering Passive Mode (127,0,0,1,82,221)\r\n"
|
141
|
+
@server.mode.should == :passive
|
135
142
|
end
|
136
143
|
|
137
144
|
it "responds with correct PASV port" do
|
@@ -153,31 +160,46 @@ describe FakeFtp::Server do
|
|
153
160
|
@client.puts "PASV"
|
154
161
|
@client.gets.should == "502 Aww hell no, use Active\r\n"
|
155
162
|
end
|
163
|
+
end
|
156
164
|
|
157
|
-
|
158
|
-
|
165
|
+
context 'active' do
|
166
|
+
before :each do
|
159
167
|
@client = TCPSocket.open('127.0.0.1', 21212)
|
160
168
|
@client.gets
|
169
|
+
|
170
|
+
@data_server = ::TCPServer.new('127.0.0.1', 21216)
|
171
|
+
@data_connection = Thread.new do
|
172
|
+
@server_client = @data_server.accept
|
173
|
+
@server_client.should_not be_nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
after :each do
|
178
|
+
@data_server.close
|
179
|
+
@data_server = nil
|
180
|
+
@data_connection = nil
|
181
|
+
@client.close
|
182
|
+
end
|
183
|
+
|
184
|
+
it "accepts PORT and connects to port" do
|
161
185
|
@client.puts "PORT 127,0,0,1,82,224"
|
162
|
-
@client.gets.should == "
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
# @connected.should be_true
|
180
|
-
# @testing = false
|
186
|
+
@client.gets.should == "200 Okay\r\n"
|
187
|
+
|
188
|
+
@data_connection.join
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should switch to :active on port command" do
|
192
|
+
@server.mode.should == :active
|
193
|
+
@client.puts 'PASV'
|
194
|
+
@client.gets
|
195
|
+
@server.mode.should == :passive
|
196
|
+
|
197
|
+
@client.puts "PORT 127,0,0,1,82,224"
|
198
|
+
@client.gets.should == "200 Okay\r\n"
|
199
|
+
|
200
|
+
@data_connection.join
|
201
|
+
|
202
|
+
@server.mode.should == :active
|
181
203
|
end
|
182
204
|
end
|
183
205
|
|
@@ -273,15 +295,58 @@ describe FakeFtp::Server do
|
|
273
295
|
@client.gets.should == "504 We don't allow those\r\n"
|
274
296
|
end
|
275
297
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
298
|
+
context 'passive' do
|
299
|
+
before :each do
|
300
|
+
@client.puts 'PASV'
|
301
|
+
@client.gets.should == "227 Entering Passive Mode (127,0,0,1,82,221)\r\n"
|
302
|
+
end
|
303
|
+
|
304
|
+
it "accepts STOR with filename" do
|
305
|
+
@client.puts "STOR some_file"
|
306
|
+
@client.gets.should == "125 Do it!\r\n"
|
307
|
+
@data_client = TCPSocket.open('127.0.0.1', 21213)
|
308
|
+
@data_client.puts "1234567890"
|
309
|
+
@data_client.close
|
310
|
+
@client.gets.should == "226 Did it!\r\n"
|
311
|
+
@server.files.should include('some_file')
|
312
|
+
@server.file('some_file').bytes.should == 10
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'active' do
|
317
|
+
before :each do
|
318
|
+
@data_server = ::TCPServer.new('127.0.0.1', 21216)
|
319
|
+
@data_connection = Thread.new do
|
320
|
+
@server_client = @data_server.accept
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
after :each do
|
325
|
+
@data_server.close
|
326
|
+
@data_connection = nil
|
327
|
+
@data_server = nil
|
328
|
+
end
|
329
|
+
|
330
|
+
it "sends error message if no PORT received" do
|
331
|
+
@client.puts "STOR some_file"
|
332
|
+
@client.gets.should == "425 Ain't no data port!\r\n"
|
333
|
+
end
|
334
|
+
|
335
|
+
it "accepts STOR with filename" do
|
336
|
+
@client.puts "PORT 127,0,0,1,82,224"
|
337
|
+
@client.gets.should == "200 Okay\r\n"
|
338
|
+
|
339
|
+
@client.puts "STOR some_other_file"
|
340
|
+
@client.gets.should == "125 Do it!\r\n"
|
341
|
+
|
342
|
+
@data_connection.join
|
343
|
+
@server_client.puts "12345"
|
344
|
+
@server_client.close
|
345
|
+
|
346
|
+
@client.gets.should == "226 Did it!\r\n"
|
347
|
+
@server.files.should include('some_other_file')
|
348
|
+
@server.file('some_other_file').bytes.should == 5
|
349
|
+
end
|
285
350
|
end
|
286
351
|
end
|
287
352
|
end
|
@@ -290,28 +355,29 @@ describe FakeFtp::Server do
|
|
290
355
|
before :each do
|
291
356
|
@ftp = Net::FTP.new
|
292
357
|
end
|
358
|
+
|
359
|
+
after :each do
|
360
|
+
@ftp.close
|
361
|
+
end
|
362
|
+
|
293
363
|
it 'should accept ftp connections' do
|
294
364
|
proc { @ftp.connect('127.0.0.1', 21212) }.should_not raise_error
|
295
|
-
proc { @ftp.close }.should_not raise_error
|
296
365
|
end
|
297
366
|
|
298
367
|
it "should allow anonymous authentication" do
|
299
368
|
@ftp.connect('127.0.0.1', 21212)
|
300
369
|
proc { @ftp.login }.should_not raise_error
|
301
|
-
@ftp.close
|
302
370
|
end
|
303
371
|
|
304
372
|
it "should allow named authentication" do
|
305
373
|
@ftp.connect('127.0.0.1', 21212)
|
306
374
|
proc { @ftp.login('someone', 'password') }.should_not raise_error
|
307
|
-
@ftp.close
|
308
375
|
end
|
309
376
|
|
310
377
|
it "should allow client to quit" do
|
311
378
|
@ftp.connect('127.0.0.1', 21212)
|
312
379
|
proc { @ftp.login('someone', 'password') }.should_not raise_error
|
313
380
|
proc { @ftp.quit }.should_not raise_error
|
314
|
-
@ftp.close
|
315
381
|
end
|
316
382
|
|
317
383
|
it "should put files using PASV" do
|
@@ -325,6 +391,17 @@ describe FakeFtp::Server do
|
|
325
391
|
@server.file('text_file.txt').bytes.should == 20
|
326
392
|
end
|
327
393
|
|
394
|
+
it "should put files using active" do
|
395
|
+
File.stat(@text_filename).size.should == 20
|
396
|
+
|
397
|
+
@ftp.connect('127.0.0.1', 21212)
|
398
|
+
@ftp.passive = false
|
399
|
+
proc { @ftp.put(@text_filename) }.should_not raise_error
|
400
|
+
|
401
|
+
@server.files.should include('text_file.txt')
|
402
|
+
@server.file('text_file.txt').bytes.should == 20
|
403
|
+
end
|
404
|
+
|
328
405
|
xit "should disconnect clients on close" do
|
329
406
|
# TODO: when this succeeds, we can care less about manually closing clients
|
330
407
|
# otherwise we get a CLOSE_WAIT process hanging around that blocks our port
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fake_ftp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Colin Shield
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-03-
|
19
|
+
date: 2011-03-06 00:00:00 -08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|