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.
@@ -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
- * Active file upload
44
+ * files should track if uploaded via active or passive
47
45
 
48
46
  References
49
47
  ----------
@@ -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
- # remote = remote.split(',')
113
- # remote_port = remote[4].to_i * 256 + remote[5].to_i
114
- # unless @data_connection.nil?
115
- # @data_connection.close
116
- # @data_connection = nil
117
- # end
118
- # puts remote_port
119
- # @data_connection = ::TCPSocket.open('127.0.0.1', remote_port)
120
- # '200 Okay'
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
- respond_with('125 Do it!')
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
- data_client = @data_server.accept
138
- data = data_client.recv(1024)
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
 
@@ -1,3 +1,3 @@
1
1
  module FakeFtp
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -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
- it "does not accept PORT (yet)" do
158
- ## TODO this test can go away once the following pending test succeeds
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 == "500 Not implemented yet\r\n"
163
- end
164
-
165
- xit "accepts PORT and connects to port" do
166
- # @testing = true
167
- # @data_server = ::TCPServer.new('127.0.0.1', 21216)
168
- # @data_connection = Thread.new do
169
- # while @testing
170
- # @server_client = @data_connection.accept
171
- # @server_connection = Thread.new(@server_client) do |socket|
172
- # @connected = true
173
- # end
174
- # end
175
- # end
176
- # @client.gets
177
- # @client.puts "PORT 127,0,0,1,82,224"
178
- # @client.gets.should == "200 Okay\r\n"
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
- it "accepts STOR with filename" do
277
- @client.puts "STOR some_file"
278
- @client.gets.should == "125 Do it!\r\n"
279
- @data_client = TCPSocket.open('127.0.0.1', 21213)
280
- @data_client.puts "1234567890"
281
- @data_client.close
282
- @client.gets.should == "226 Did it!\r\n"
283
- @server.files.should include('some_file')
284
- @server.file('some_file').bytes.should == 10
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: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
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-05 00:00:00 -08:00
19
+ date: 2011-03-06 00:00:00 -08:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency