fake_ftp 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|