fake_ftp 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .idea
2
+ pkg/*
3
+ *.gem
4
+ .bundle
5
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ree@fake_ftp --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fake_ftp.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fake_ftp (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ rake (0.8.7)
11
+ rspec (2.5.0)
12
+ rspec-core (~> 2.5.0)
13
+ rspec-expectations (~> 2.5.0)
14
+ rspec-mocks (~> 2.5.0)
15
+ rspec-core (2.5.1)
16
+ rspec-expectations (2.5.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.5.0)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (>= 1.0.10)
25
+ fake_ftp!
26
+ rake (>= 0.8.7)
27
+ rspec (> 2)
data/README.markdown ADDED
@@ -0,0 +1,81 @@
1
+ FakeFtp
2
+ =======
3
+
4
+ This is a gem that allows you to test FTP implementations in ruby. It is a minimal single-client FTP server
5
+ that can be bound to any arbitrary port on localhost.
6
+
7
+ Why?
8
+ ----
9
+
10
+ We want to ensure that our code works, in a way that is agnostic to the implementation used (unlike with stubs or mocks).
11
+
12
+ How
13
+ ---
14
+
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.
17
+
18
+ Note: Only passive FTP is currently implemented
19
+
20
+ Usage
21
+ -----
22
+
23
+ require 'fake_ftp'
24
+ require 'net/ftp'
25
+
26
+ server = FakeFtp::Server.new(21212, 21213)
27
+ ## 21212 is the control port, which is used by FTP for the primary connection
28
+ ## 21213 is the data port, used in FTP passive mode to send file contents
29
+ server.start
30
+
31
+ ftp = Net::FTP.new
32
+ ftp.connect('127.0.0.1', 21212)
33
+ ftp.login('user', 'password')
34
+ ftp.passive = true
35
+ ftp.put('some_file.txt')
36
+ ftp.close
37
+
38
+ server.stop
39
+
40
+ TODO
41
+ ----
42
+
43
+ * Active file upload
44
+ * Matchers
45
+
46
+ References
47
+ ----------
48
+
49
+ * http://rubyforge.org/projects/ftpd/ - a simple ftp daemon written by Chris Wanstrath
50
+ * http://ruby-doc.org/stdlib/libdoc/gserver/rdoc/index.html - a generic server in the Ruby standard library, by John W Small
51
+
52
+ Contributors
53
+ ------------
54
+
55
+ * Eric Saxby
56
+ * Colin Shield
57
+
58
+ License
59
+ -------
60
+
61
+ The MIT License
62
+
63
+ Copyright (c) 2011 Eric Saxby
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining a copy
66
+ of this software and associated documentation files (the "Software"), to deal
67
+ in the Software without restriction, including without limitation the rights
68
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69
+ copies of the Software, and to permit persons to whom the Software is
70
+ furnished to do so, subject to the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be included in
73
+ all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
76
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
77
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
79
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
81
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new('spec')
8
+
9
+ # If you want to make this the default task
10
+ task :default => :spec
data/fake_ftp.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fake_ftp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fake_ftp"
7
+ s.version = FakeFtp::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Colin Shield", "Eric Saxby"]
10
+ s.email = ["sax+github@livinginthepast.org"]
11
+ s.homepage = "http://rubygems.org/gems/fake_ftp"
12
+ s.summary = %q{Creates a fake FTP server for use in testing}
13
+ s.description = %q{Testing FTP? Use this!}
14
+
15
+ s.required_rubygems_version = ">= 1.3.6"
16
+ s.rubyforge_project = "fake_ftp"
17
+
18
+ s.add_development_dependency "bundler", '>=1.0.10'
19
+ s.add_development_dependency "rspec", '>2'
20
+ s.add_development_dependency "rake", '>=0.8.7'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,155 @@
1
+ require 'socket'
2
+ require "thread"
3
+
4
+ module FakeFtp
5
+ class Server
6
+
7
+ attr_accessor :directory, :port, :passive_port
8
+ attr_reader :files
9
+
10
+ CMDS = %w[acct cwd cdup pass pasv port pwd quit stor type user]
11
+ LNBK = "\r\n"
12
+
13
+ def initialize(control_port = 21, data_port = nil, options = {})
14
+ self.port = control_port
15
+ self.passive_port = data_port
16
+ raise(Errno::EADDRINUSE, "#{port}") if is_running?
17
+ raise(Errno::EADDRINUSE, "#{passive_port}") if passive_port && is_running?(passive_port)
18
+ @connection = nil
19
+ @data = nil
20
+ @options = options
21
+ @files = []
22
+ self.directory = "#{Rails.root}/tmp/ftp" rescue '/tmp'
23
+ end
24
+
25
+ def start
26
+ @started = true
27
+ @server = ::TCPServer.new('127.0.0.1', port)
28
+ @thread = Thread.new do
29
+ while @started
30
+ @client = @server.accept
31
+ respond_with('200 Can has FTP?')
32
+ @connection = Thread.new(@client) do |socket|
33
+ while @started && !socket.nil? && !socket.closed?
34
+ respond_with parse(socket.gets)
35
+ end
36
+ @client.close
37
+ @client = nil
38
+ end
39
+ end
40
+ @server.close
41
+ @server = nil
42
+ end
43
+
44
+ if passive_port
45
+ @data_server = ::TCPserver.new('127.0.0.1', passive_port)
46
+ end
47
+ end
48
+
49
+ def stop
50
+ @started = false
51
+ @client.close if @client
52
+ @server.close if @server
53
+ @server = nil
54
+ @data_server.close if @data_server
55
+ @data_server = nil
56
+ end
57
+
58
+ def is_running?(tcp_port = nil)
59
+ service = `lsof -w -n -i tcp:#{tcp_port || port}`
60
+ !service.nil? && service != ''
61
+ end
62
+
63
+ private
64
+
65
+ def respond_with(stuff)
66
+ @client.print stuff << LNBK unless stuff.nil? or @client.nil? or @client.closed?
67
+ end
68
+
69
+ def parse(request)
70
+ return if request.nil?
71
+ puts request if @options[:debug]
72
+ command = request[0, 4].downcase.strip
73
+ contents = request.split
74
+ message = contents[1..contents.length]
75
+ case command
76
+ when *CMDS
77
+ __send__ "_#{command}", message
78
+ else
79
+ '500 Unknown command'
80
+ end
81
+ end
82
+
83
+ def _acct(*args)
84
+ '230 WHATEVER!'
85
+ end
86
+
87
+ def _cwd(*args)
88
+ '250 OK!'
89
+ end
90
+ alias :_cdup :_cwd
91
+
92
+ def _pass(*args)
93
+ '230 logged in'
94
+ end
95
+
96
+ def _pasv(*args)
97
+ if passive_port
98
+ p1 = (passive_port / 256).to_i
99
+ p2 = passive_port % 256
100
+ "227 Entering Passive Mode (127,0,0,1,#{p1},#{p2})"
101
+ else
102
+ '502 Aww hell no, use Active'
103
+ end
104
+ end
105
+
106
+ def _port(remote)
107
+ # remote = remote.split(',')
108
+ # remote_port = remote[4].to_i * 256 + remote[5].to_i
109
+ # unless @data_connection.nil?
110
+ # @data_connection.close
111
+ # @data_connection = nil
112
+ # end
113
+ # puts remote_port
114
+ # @data_connection = ::TCPSocket.open('127.0.0.1', remote_port)
115
+ # '200 Okay'
116
+ '500 Not implemented yet'
117
+ end
118
+
119
+ def _pwd(*args)
120
+ "257 \"#{self.directory}\" is current directory"
121
+ end
122
+
123
+ def _quit(*args)
124
+ respond_with '221 OMG bye!'
125
+ @client.close if @client
126
+ @client = nil
127
+ end
128
+
129
+ def _stor(filename)
130
+ @files << File.basename(filename.to_s)
131
+ respond_with('125 Do it!')
132
+
133
+ data_client = @data_server.accept
134
+ @data = data_client.recv(1024)
135
+
136
+ data_client.close
137
+ '226 Did it!'
138
+ end
139
+
140
+ def _type(type = 'A')
141
+ case type.to_s
142
+ when 'A'
143
+ '200 Type set to A.'
144
+ when 'I'
145
+ '200 Type set to I.'
146
+ else
147
+ '504 We don\'t allow those'
148
+ end
149
+ end
150
+
151
+ def _user(name = '')
152
+ (name.to_s == 'anonymous') ? '230 logged in' : '331 send your password'
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,3 @@
1
+ module FakeFtp
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fake_ftp.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'fake_ftp/server'
2
+
3
+ module FakeFtp
4
+ end
Binary file
@@ -0,0 +1 @@
1
+ Hello im a text file
@@ -0,0 +1,353 @@
1
+ require "spec_helper.rb"
2
+ require 'net/ftp'
3
+
4
+ describe FakeFtp::Server do
5
+
6
+ before :each do
7
+ @directory = File.expand_path("../fixtures/destination", File.dirname(__FILE__))
8
+ @text_filename = File.expand_path("../../fixtures/text_file.txt", File.dirname(__FILE__))
9
+ @bin_filename = File.expand_path("../../fixtures/invisible_bike.jpg", File.dirname(__FILE__))
10
+ end
11
+
12
+ after :each do
13
+ FileUtils.rm_rf(@directory+"/*")
14
+ end
15
+
16
+ context 'setup' do
17
+ it "starts a server on port n" do
18
+ server = FakeFtp::Server.new(21212)
19
+ server.port.should == 21212
20
+ end
21
+
22
+ it "should defaults to port 21" do
23
+ server = FakeFtp::Server.new
24
+ server.port.should == 21
25
+ end
26
+
27
+ it "starts a passive server on port p" do
28
+ server = FakeFtp::Server.new(21212, 21213)
29
+ server.passive_port.should == 21213
30
+ end
31
+
32
+ it "should start and stop" do
33
+ server = FakeFtp::Server.new(21212)
34
+ server.is_running?.should be_false
35
+ server.start
36
+ server.is_running?.should be_true
37
+ server.stop
38
+ server.is_running?.should be_false
39
+ end
40
+
41
+ it "should start and stop passive port" do
42
+ server = FakeFtp::Server.new(21212, 21213)
43
+ server.is_running?(21213).should be_false
44
+ server.start
45
+ server.is_running?(21213).should be_true
46
+ server.stop
47
+ server.is_running?(21213).should be_false
48
+ end
49
+
50
+ it "should raise if attempting to use a bound port" do
51
+ server = FakeFtp::Server.new(21212)
52
+ server.start
53
+ proc { FakeFtp::Server.new(21212) }.should raise_error(Errno::EADDRINUSE, "Address already in use - 21212")
54
+ server.stop
55
+ end
56
+
57
+ it "should raise if attempting to use a bound passive_port" do
58
+ server = FakeFtp::Server.new(21212, 21213)
59
+ server.start
60
+ proc { FakeFtp::Server.new(21214, 21213) }.should raise_error(Errno::EADDRINUSE, "Address already in use - 21213")
61
+ server.stop
62
+ end
63
+
64
+ it "can be configured with a directory store" do
65
+ server = FakeFtp::Server.new
66
+ server.directory = @directory
67
+ server.directory.should == @directory
68
+ end
69
+
70
+ it "should default directory to /tmp if Rails.root does not exist" do
71
+ server = FakeFtp::Server.new
72
+ server.directory.should == '/tmp'
73
+ end
74
+
75
+ it "should default directory to Rails.root/tmp/ftp if exists" do
76
+ module Rails; end
77
+ Rails.stub!(:root).and_return('/somewhere')
78
+ server = FakeFtp::Server.new
79
+ server.directory.should == '/somewhere/tmp/ftp'
80
+ end
81
+
82
+ it "should clean up directory after itself"
83
+
84
+ it "should raise if attempting to delete a directory with contents other than its own"
85
+ end
86
+
87
+ context 'socket' do
88
+ before :each do
89
+ @server = FakeFtp::Server.new(21212, 21213)
90
+ @server.start
91
+ end
92
+
93
+ after :each do
94
+ @server.stop
95
+ @server = nil
96
+ end
97
+
98
+ context 'FTP commands' do
99
+ context 'general' do
100
+ before :each do
101
+ @client = TCPSocket.open('127.0.0.1', 21212)
102
+ end
103
+
104
+ after :each do
105
+ @client.close
106
+ end
107
+
108
+ it "should accept connections" do
109
+ @client.gets.should == "200 Can has FTP?\r\n"
110
+ end
111
+
112
+ it "should get unknown command response when nothing is sent" do
113
+ @client.gets
114
+ @client.puts
115
+ @client.gets.should == "500 Unknown command\r\n"
116
+ end
117
+
118
+ it "accepts QUIT" do
119
+ @client.gets
120
+ @client.puts "QUIT"
121
+ @client.gets.should == "221 OMG bye!\r\n"
122
+ end
123
+
124
+ it "should accept multiple commands in one session" do
125
+ @client.gets
126
+ @client.puts "USER thing"
127
+ @client.gets
128
+ @client.puts "PASS thing"
129
+ @client.gets
130
+ @client.puts "ACCT thing"
131
+ @client.gets
132
+ @client.puts "USER thing"
133
+ end
134
+ end
135
+
136
+ context 'passive' do
137
+ after :each do
138
+ @client.close
139
+ end
140
+
141
+ it "accepts PASV" do
142
+ @client = TCPSocket.open('127.0.0.1', 21212)
143
+ @client.gets
144
+ @client.puts "PASV"
145
+ @client.gets.should == "227 Entering Passive Mode (127,0,0,1,82,221)\r\n"
146
+ end
147
+
148
+ it "responds with correct PASV port" do
149
+ @server.stop
150
+ @server.passive_port = 21111
151
+ @server.start
152
+ @client = TCPSocket.open('127.0.0.1', 21212)
153
+ @client.gets
154
+ @client.puts "PASV"
155
+ @client.gets.should == "227 Entering Passive Mode (127,0,0,1,82,119)\r\n"
156
+ end
157
+
158
+ it "does not accept PASV if no port set" do
159
+ @server.stop
160
+ @server.passive_port = nil
161
+ @server.start
162
+ @client = TCPSocket.open('127.0.0.1', 21212)
163
+ @client.gets
164
+ @client.puts "PASV"
165
+ @client.gets.should == "502 Aww hell no, use Active\r\n"
166
+ end
167
+
168
+ it "does not accept PORT (yet)" do
169
+ ## TODO this test can go away once the following pending test succeeds
170
+ @client = TCPSocket.open('127.0.0.1', 21212)
171
+ @client.gets
172
+ @client.puts "PORT 127,0,0,1,82,224"
173
+ @client.gets.should == "500 Not implemented yet\r\n"
174
+ end
175
+
176
+ xit "accepts PORT and connects to port" do
177
+ # @testing = true
178
+ # @data_server = ::TCPServer.new('127.0.0.1', 21216)
179
+ # @data_connection = Thread.new do
180
+ # while @testing
181
+ # @server_client = @data_connection.accept
182
+ # @server_connection = Thread.new(@server_client) do |socket|
183
+ # @connected = true
184
+ # end
185
+ # end
186
+ # end
187
+ # @client.gets
188
+ # @client.puts "PORT 127,0,0,1,82,224"
189
+ # @client.gets.should == "200 Okay\r\n"
190
+ # @connected.should be_true
191
+ # @testing = false
192
+ end
193
+ end
194
+
195
+ context 'authentication commands' do
196
+ before :each do
197
+ @client = TCPSocket.open('127.0.0.1', 21212)
198
+ @client.gets ## connection successful response
199
+ end
200
+
201
+ after :each do
202
+ @client.close
203
+ end
204
+
205
+ it "accepts USER" do
206
+ @client.puts "USER some_dude"
207
+ @client.gets.should == "331 send your password\r\n"
208
+ end
209
+
210
+ it "accepts anonymous USER" do
211
+ @client.puts "USER anonymous"
212
+ @client.gets.should == "230 logged in\r\n"
213
+ end
214
+
215
+ it "accepts PASS" do
216
+ @client.puts "PASS password"
217
+ @client.gets.should == "230 logged in\r\n"
218
+ end
219
+
220
+ it "accepts ACCT" do
221
+ @client.puts "ACCT"
222
+ @client.gets.should == "230 WHATEVER!\r\n"
223
+ end
224
+ end
225
+
226
+ context 'directory commands' do
227
+ before :each do
228
+ @client = TCPSocket.open('127.0.0.1', 21212)
229
+ @client.gets ## connection successful response
230
+ end
231
+
232
+ after :each do
233
+ @client.close
234
+ end
235
+
236
+ it "returns directory on PWD" do
237
+ @server.directory = @directory
238
+ @client.puts "PWD"
239
+ @client.gets.should == "257 \"#{@directory}\" is current directory\r\n"
240
+ end
241
+
242
+ it "returns default directory on PWD" do
243
+ @server.directory = '/tmp'
244
+ @client.puts "PWD"
245
+ @client.gets.should == "257 \"/tmp\" is current directory\r\n"
246
+ end
247
+
248
+ it "says OK to any CWD, CDUP, without doing anything" do
249
+ directory = @server.directory
250
+ @client.puts "CWD somewhere/else"
251
+ @client.gets.should == "250 OK!\r\n"
252
+ @server.directory.should == directory
253
+ @client.puts "CDUP"
254
+ @client.gets.should == "250 OK!\r\n"
255
+ @server.directory.should == directory
256
+ end
257
+
258
+ it "does not respond to MKD" do
259
+ @client.puts "MKD some_dir"
260
+ @client.gets.should == "500 Unknown command\r\n"
261
+ end
262
+ end
263
+
264
+ context 'file commands' do
265
+ before :each do
266
+ @client = TCPSocket.open('127.0.0.1', 21212)
267
+ @client.gets ## connection successful response
268
+ end
269
+
270
+ after :each do
271
+ @client.close
272
+ end
273
+
274
+ it "accepts TYPE ascii" do
275
+ @client.puts "TYPE A"
276
+ @client.gets.should == "200 Type set to A.\r\n"
277
+ end
278
+
279
+ it "accepts TYPE image" do
280
+ @client.puts "TYPE I"
281
+ @client.gets.should == "200 Type set to I.\r\n"
282
+ end
283
+
284
+ it "does not accept TYPEs other than ascii or image" do
285
+ @client.puts "TYPE E"
286
+ @client.gets.should == "504 We don't allow those\r\n"
287
+ @client.puts "TYPE N"
288
+ @client.gets.should == "504 We don't allow those\r\n"
289
+ @client.puts "TYPE T"
290
+ @client.gets.should == "504 We don't allow those\r\n"
291
+ @client.puts "TYPE C"
292
+ @client.gets.should == "504 We don't allow those\r\n"
293
+ @client.puts "TYPE L"
294
+ @client.gets.should == "504 We don't allow those\r\n"
295
+ end
296
+
297
+ it "accepts STOR with filename" do
298
+ @client.puts "STOR some_file"
299
+ @client.gets.should == "125 Do it!\r\n"
300
+ @data_client = TCPSocket.open('127.0.0.1', 21213)
301
+ @data_client.puts "1234567890"
302
+ @data_client.close
303
+ @client.gets.should == "226 Did it!\r\n"
304
+ @server.files.should include('some_file')
305
+ end
306
+ end
307
+ end
308
+
309
+ context 'ftp client' do
310
+ before :each do
311
+ @ftp = Net::FTP.new
312
+ end
313
+ it 'should accept ftp connections' do
314
+ proc { @ftp.connect('127.0.0.1', 21212) }.should_not raise_error
315
+ proc { @ftp.close }.should_not raise_error
316
+ end
317
+
318
+ it "should allow anonymous authentication" do
319
+ @ftp.connect('127.0.0.1', 21212)
320
+ proc { @ftp.login }.should_not raise_error
321
+ @ftp.close
322
+ end
323
+
324
+ it "should allow named authentication" do
325
+ @ftp.connect('127.0.0.1', 21212)
326
+ proc { @ftp.login('someone', 'password') }.should_not raise_error
327
+ @ftp.close
328
+ end
329
+
330
+ it "should allow client to quit" do
331
+ @ftp.connect('127.0.0.1', 21212)
332
+ proc { @ftp.login('someone', 'password') }.should_not raise_error
333
+ proc { @ftp.quit }.should_not raise_error
334
+ @ftp.close
335
+ end
336
+
337
+ it "should put files to directory store using PASV" do
338
+ @ftp.connect('127.0.0.1', 21212)
339
+ @ftp.passive = true
340
+ proc { @ftp.put(@text_filename) }.should_not raise_error
341
+ @server.files.should include('text_file.txt')
342
+ end
343
+
344
+ xit "should disconnect clients on close" do
345
+ # TODO: when this succeeds, we can care less about manually closing clients
346
+ # otherwise we get a CLOSE_WAIT process hanging around that blocks our port
347
+ @ftp.connect('127.0.0.1', 21212)
348
+ @server.stop
349
+ @ftp.closed?.should be_true
350
+ end
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__), '**','*')
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+
8
+ require 'rspec'
9
+ require 'fake_ftp' # and any other gems you need
10
+
11
+ RSpec.configure do |config|
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fake_ftp
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Colin Shield
14
+ - Eric Saxby
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-02-28 00:00:00 -08:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: bundler
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 1
33
+ - 0
34
+ - 10
35
+ version: 1.0.10
36
+ type: :development
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">"
45
+ - !ruby/object:Gem::Version
46
+ hash: 7
47
+ segments:
48
+ - 2
49
+ version: "2"
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rake
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 49
61
+ segments:
62
+ - 0
63
+ - 8
64
+ - 7
65
+ version: 0.8.7
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: Testing FTP? Use this!
69
+ email:
70
+ - sax+github@livinginthepast.org
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files: []
76
+
77
+ files:
78
+ - .gitignore
79
+ - .rvmrc
80
+ - Gemfile
81
+ - Gemfile.lock
82
+ - README.markdown
83
+ - Rakefile
84
+ - fake_ftp.gemspec
85
+ - lib/fake_ftp.rb
86
+ - lib/fake_ftp/server.rb
87
+ - lib/fake_ftp/version.rb
88
+ - spec/fixtures/invisible_bike.jpg
89
+ - spec/fixtures/text_file.txt
90
+ - spec/models/fake_ftp/server_spec.rb
91
+ - spec/spec_helper.rb
92
+ has_rdoc: true
93
+ homepage: http://rubygems.org/gems/fake_ftp
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options: []
98
+
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 23
116
+ segments:
117
+ - 1
118
+ - 3
119
+ - 6
120
+ version: 1.3.6
121
+ requirements: []
122
+
123
+ rubyforge_project: fake_ftp
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Creates a fake FTP server for use in testing
128
+ test_files:
129
+ - spec/fixtures/invisible_bike.jpg
130
+ - spec/fixtures/text_file.txt
131
+ - spec/models/fake_ftp/server_spec.rb
132
+ - spec/spec_helper.rb