fake_ftp 0.2.0 → 0.3.0
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 +4 -4
- data/.codeclimate.yml +16 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +7 -0
- data/.simplecov +6 -0
- data/.travis.yml +27 -2
- data/CHANGELOG.md +136 -0
- data/Gemfile +9 -7
- data/Guardfile +5 -4
- data/LICENSE.md +20 -0
- data/README.md +30 -63
- data/Rakefile +12 -7
- data/fake_ftp.gemspec +16 -17
- data/lib/fake_ftp.rb +3 -2
- data/lib/fake_ftp/file.rb +11 -5
- data/lib/fake_ftp/server.rb +138 -261
- data/lib/fake_ftp/server_commands.rb +6 -0
- data/lib/fake_ftp/server_commands/acct.rb +11 -0
- data/lib/fake_ftp/server_commands/cdup.rb +11 -0
- data/lib/fake_ftp/server_commands/cwd.rb +13 -0
- data/lib/fake_ftp/server_commands/dele.rb +25 -0
- data/lib/fake_ftp/server_commands/list.rb +39 -0
- data/lib/fake_ftp/server_commands/mdtm.rb +17 -0
- data/lib/fake_ftp/server_commands/mkd.rb +11 -0
- data/lib/fake_ftp/server_commands/nlst.rb +32 -0
- data/lib/fake_ftp/server_commands/pass.rb +11 -0
- data/lib/fake_ftp/server_commands/pasv.rb +15 -0
- data/lib/fake_ftp/server_commands/port.rb +23 -0
- data/lib/fake_ftp/server_commands/pwd.rb +11 -0
- data/lib/fake_ftp/server_commands/quit.rb +13 -0
- data/lib/fake_ftp/server_commands/retr.rb +32 -0
- data/lib/fake_ftp/server_commands/rnfr.rb +18 -0
- data/lib/fake_ftp/server_commands/rnto.rb +22 -0
- data/lib/fake_ftp/server_commands/site.rb +11 -0
- data/lib/fake_ftp/server_commands/size.rb +11 -0
- data/lib/fake_ftp/server_commands/stor.rb +30 -0
- data/lib/fake_ftp/server_commands/type.rb +18 -0
- data/lib/fake_ftp/server_commands/user.rb +12 -0
- data/lib/fake_ftp/server_commands/wat.rb +33 -0
- data/lib/fake_ftp/version.rb +3 -1
- data/spec/functional/server_spec.rb +459 -358
- data/spec/integration/server_spec.rb +39 -29
- data/spec/models/fake_ftp/file_spec.rb +22 -21
- data/spec/models/fake_ftp/server_spec.rb +33 -32
- data/spec/spec_helper.rb +98 -14
- metadata +32 -3
@@ -1,10 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'net/ftp'
|
3
4
|
|
4
|
-
describe FakeFtp::Server, 'with ftp client' do
|
5
|
-
let(:server) { FakeFtp::Server.new(
|
6
|
-
let(:client) { Net::FTP.new }
|
7
|
-
let(:text_filename)
|
5
|
+
describe FakeFtp::Server, 'with ftp client', integration: true do
|
6
|
+
let(:server) { FakeFtp::Server.new(21_212, 21_213, absolute: true) }
|
7
|
+
let(:client) { Net::FTP.new(nil, debug_mode: ENV['DEBUG'] == '1') }
|
8
|
+
let(:text_filename) do
|
9
|
+
File.expand_path('../../fixtures/text_file.txt', __FILE__)
|
10
|
+
end
|
8
11
|
|
9
12
|
before { server.start }
|
10
13
|
|
@@ -14,29 +17,29 @@ describe FakeFtp::Server, 'with ftp client' do
|
|
14
17
|
end
|
15
18
|
|
16
19
|
it 'should accept connections' do
|
17
|
-
expect { client.connect('127.0.0.1',
|
20
|
+
expect { client.connect('127.0.0.1', 21_212) }.to_not raise_error
|
18
21
|
end
|
19
22
|
|
20
|
-
context
|
21
|
-
before { client.connect(
|
23
|
+
context 'with client' do
|
24
|
+
before { client.connect('127.0.0.1', 21_212) }
|
22
25
|
|
23
|
-
it
|
26
|
+
it 'should allow anonymous authentication' do
|
24
27
|
expect { client.login }.to_not raise_error
|
25
28
|
end
|
26
29
|
|
27
|
-
it
|
30
|
+
it 'should allow named authentication' do
|
28
31
|
expect { client.login('someone', 'password') }.to_not raise_error
|
29
32
|
end
|
30
33
|
|
31
|
-
it
|
34
|
+
it 'should allow client to quit' do
|
32
35
|
expect { client.login('someone', 'password') }.to_not raise_error
|
33
36
|
expect { client.quit }.to_not raise_error
|
34
37
|
end
|
35
38
|
|
36
|
-
it
|
37
|
-
filename = 'someone'
|
39
|
+
it 'should allow mtime' do
|
40
|
+
filename = '/pub/someone'
|
38
41
|
time = Time.now
|
39
|
-
server.add_file(filename,
|
42
|
+
server.add_file(filename, 'some data', time)
|
40
43
|
|
41
44
|
client.passive = false
|
42
45
|
mtime = client.mtime(filename)
|
@@ -47,35 +50,42 @@ describe FakeFtp::Server, 'with ftp client' do
|
|
47
50
|
expect(mtime.to_s).to eql(time.to_s)
|
48
51
|
end
|
49
52
|
|
50
|
-
it
|
53
|
+
it 'should put files using PASV' do
|
51
54
|
expect(File.stat(text_filename).size).to eql(20)
|
52
55
|
|
53
56
|
client.passive = true
|
54
57
|
expect { client.put(text_filename) }.to_not raise_error
|
55
58
|
|
56
|
-
expect(server.files).to include('text_file.txt')
|
57
|
-
expect(server.file('text_file.txt').bytes).to eql(20)
|
58
|
-
expect(server.file('text_file.txt')).to be_passive
|
59
|
-
expect(server.file('text_file.txt')).to_not be_active
|
59
|
+
expect(server.files).to include('/pub/text_file.txt')
|
60
|
+
expect(server.file('/pub/text_file.txt').bytes).to eql(20)
|
61
|
+
expect(server.file('/pub/text_file.txt')).to be_passive
|
62
|
+
expect(server.file('/pub/text_file.txt')).to_not be_active
|
60
63
|
end
|
61
64
|
|
62
|
-
it
|
65
|
+
it 'should put files using active' do
|
63
66
|
expect(File.stat(text_filename).size).to eql(20)
|
64
67
|
|
65
68
|
client.passive = false
|
66
69
|
expect { client.put(text_filename) }.to_not raise_error
|
67
70
|
|
68
|
-
expect(server.files).to include('text_file.txt')
|
69
|
-
expect(server.file('text_file.txt').bytes).to eql(20)
|
70
|
-
expect(server.file('text_file.txt')).to_not be_passive
|
71
|
-
expect(server.file('text_file.txt')).to be_active
|
71
|
+
expect(server.files).to include('/pub/text_file.txt')
|
72
|
+
expect(server.file('/pub/text_file.txt').bytes).to eql(20)
|
73
|
+
expect(server.file('/pub/text_file.txt')).to_not be_passive
|
74
|
+
expect(server.file('/pub/text_file.txt')).to be_active
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should allow client to execute SITE command' do
|
78
|
+
expect { client.site('umask') }.to_not raise_error
|
72
79
|
end
|
73
80
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
expect
|
81
|
+
it 'should be able to delete files added using put' do
|
82
|
+
expect(File.stat(text_filename).size).to eql(20)
|
83
|
+
|
84
|
+
client.passive = false
|
85
|
+
expect { client.put(text_filename) }.to_not raise_error
|
86
|
+
expect(server.files).to include('/pub/text_file.txt')
|
87
|
+
expect { client.delete(text_filename) }.to_not raise_error
|
88
|
+
expect(server.files).to_not include('/pub/text_file.txt')
|
79
89
|
end
|
80
90
|
end
|
81
91
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe FakeFtp::File do
|
4
4
|
context 'attributes' do
|
@@ -6,59 +6,60 @@ describe FakeFtp::File do
|
|
6
6
|
@file = FakeFtp::File.new
|
7
7
|
end
|
8
8
|
|
9
|
-
it
|
10
|
-
@file.name =
|
11
|
-
expect(@file.name).to eql(
|
9
|
+
it 'has a name attribute' do
|
10
|
+
@file.name = 'some name'
|
11
|
+
expect(@file.name).to eql('some name')
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
14
|
+
it 'has a last_modified_time attribute' do
|
15
15
|
now = Time.now
|
16
16
|
@file.last_modified_time = now
|
17
17
|
expect(@file.last_modified_time).to eql(now)
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
20
|
+
it 'has a bytes attribute' do
|
21
21
|
@file.bytes = 87
|
22
22
|
expect(@file.bytes).to eql(87)
|
23
23
|
end
|
24
24
|
|
25
|
-
it
|
25
|
+
it 'has a data attribute' do
|
26
26
|
@file.data = 'some data'
|
27
27
|
expect(@file.data).to eql('some data')
|
28
|
-
expect(@file.bytes).to eql(
|
28
|
+
expect(@file.bytes).to eql(9)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'setup' do
|
33
|
-
it
|
33
|
+
it 'can be initialized without attributes' do
|
34
34
|
file = FakeFtp::File.new
|
35
35
|
expect(file.name).to be_nil
|
36
36
|
expect(file.bytes).to be_nil
|
37
37
|
expect(file.instance_variable_get(:@type)).to be_nil
|
38
38
|
end
|
39
39
|
|
40
|
-
it
|
40
|
+
it 'can be initialized with name' do
|
41
41
|
file = FakeFtp::File.new('filename')
|
42
42
|
expect(file.name).to eql('filename')
|
43
43
|
expect(file.bytes).to be_nil
|
44
44
|
expect(file.instance_variable_get(:@type)).to be_nil
|
45
45
|
end
|
46
46
|
|
47
|
-
it
|
47
|
+
it 'can be initialized with name and bytes' do
|
48
48
|
file = FakeFtp::File.new('filename', 104)
|
49
49
|
expect(file.name).to eql('filename')
|
50
50
|
expect(file.bytes).to eql(104)
|
51
51
|
expect(file.instance_variable_get(:@type)).to be_nil
|
52
52
|
end
|
53
53
|
|
54
|
-
it
|
54
|
+
it 'can be initialized with name and bytes and type' do
|
55
55
|
file = FakeFtp::File.new('filename', 104, :passive)
|
56
56
|
expect(file.name).to eql('filename')
|
57
57
|
expect(file.bytes).to eql(104)
|
58
58
|
expect(file.instance_variable_get(:@type)).to eql(:passive)
|
59
59
|
end
|
60
60
|
|
61
|
-
it
|
61
|
+
it 'can be initialized with name and bytes and type ' \
|
62
|
+
'and last_modified_time' do
|
62
63
|
time = Time.now
|
63
64
|
file = FakeFtp::File.new('filename', 104, :passive, time)
|
64
65
|
expect(file.name).to eql('filename')
|
@@ -73,14 +74,14 @@ describe FakeFtp::File do
|
|
73
74
|
@file = FakeFtp::File.new
|
74
75
|
end
|
75
76
|
|
76
|
-
it
|
77
|
+
it 'should be true if type is :passive' do
|
77
78
|
@file.type = :passive
|
78
|
-
expect(@file.passive?).to
|
79
|
+
expect(@file.passive?).to be true
|
79
80
|
end
|
80
81
|
|
81
|
-
it
|
82
|
+
it 'should be false if type is :active' do
|
82
83
|
@file.type = :active
|
83
|
-
expect(@file.passive?).to
|
84
|
+
expect(@file.passive?).to be false
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
@@ -89,14 +90,14 @@ describe FakeFtp::File do
|
|
89
90
|
@file = FakeFtp::File.new
|
90
91
|
end
|
91
92
|
|
92
|
-
it
|
93
|
+
it 'should be true if type is :active' do
|
93
94
|
@file.type = :active
|
94
|
-
expect(@file.active?).to
|
95
|
+
expect(@file.active?).to be true
|
95
96
|
end
|
96
97
|
|
97
|
-
it
|
98
|
+
it 'should be false if type is :passive' do
|
98
99
|
@file.type = :passive
|
99
|
-
expect(@file.active?).to
|
100
|
+
expect(@file.active?).to be false
|
100
101
|
end
|
101
102
|
end
|
102
103
|
end
|
@@ -1,76 +1,77 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe FakeFtp::Server, 'setup' do
|
4
|
-
it
|
5
|
-
server = FakeFtp::Server.new(
|
6
|
-
expect(server.port).to eql(
|
4
|
+
it 'starts a server on port n' do
|
5
|
+
server = FakeFtp::Server.new(21_212)
|
6
|
+
expect(server.port).to eql(21_212)
|
7
7
|
end
|
8
8
|
|
9
|
-
it
|
9
|
+
it 'should defaults to port 21' do
|
10
10
|
server = FakeFtp::Server.new
|
11
11
|
expect(server.port).to eql(21)
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
15
|
-
server = FakeFtp::Server.new(
|
16
|
-
expect(server.passive_port).to eql(
|
14
|
+
it 'starts a passive server on port p' do
|
15
|
+
server = FakeFtp::Server.new(21_212, 21_213)
|
16
|
+
expect(server.passive_port).to eql(21_213)
|
17
17
|
end
|
18
18
|
|
19
|
-
it
|
20
|
-
server = FakeFtp::Server.new(
|
21
|
-
expect(server.
|
19
|
+
it 'should start and stop' do
|
20
|
+
server = FakeFtp::Server.new(21_212)
|
21
|
+
expect(server.running?).to be false
|
22
22
|
server.start
|
23
|
-
expect(server.
|
23
|
+
expect(server.running?).to be true
|
24
24
|
server.stop
|
25
|
-
expect(server.
|
25
|
+
expect(server.running?).to be false
|
26
26
|
end
|
27
27
|
|
28
|
-
it
|
29
|
-
server = FakeFtp::Server.new(
|
28
|
+
it 'should default :mode to :active' do
|
29
|
+
server = FakeFtp::Server.new(21_212, 21_213)
|
30
30
|
expect(server.mode).to eql(:active)
|
31
31
|
end
|
32
32
|
|
33
|
-
it
|
34
|
-
server = FakeFtp::Server.new(
|
35
|
-
expect(server.
|
33
|
+
it 'should start and stop passive port' do
|
34
|
+
server = FakeFtp::Server.new(21_212, 21_213)
|
35
|
+
expect(server.running?(21_213)).to be false
|
36
36
|
server.start
|
37
|
-
expect(server.
|
37
|
+
expect(server.running?(21_213)).to be true
|
38
38
|
server.stop
|
39
|
-
expect(server.
|
39
|
+
expect(server.running?(21_213)).to be false
|
40
40
|
end
|
41
41
|
|
42
|
-
it
|
43
|
-
server = FakeFtp::Server.new(
|
42
|
+
it 'should raise if attempting to use a bound port' do
|
43
|
+
server = FakeFtp::Server.new(21_212)
|
44
44
|
server.start
|
45
|
-
expect { FakeFtp::Server.new(
|
45
|
+
expect { FakeFtp::Server.new(21_212) }
|
46
|
+
.to raise_error(Errno::EADDRINUSE, 'Address already in use - 21212')
|
46
47
|
server.stop
|
47
48
|
end
|
48
49
|
|
49
|
-
it
|
50
|
-
server = FakeFtp::Server.new(
|
50
|
+
it 'should raise if attempting to use a bound passive_port' do
|
51
|
+
server = FakeFtp::Server.new(21_212, 21_213)
|
51
52
|
server.start
|
52
|
-
expect { FakeFtp::Server.new(
|
53
|
+
expect { FakeFtp::Server.new(21_214, 21_213) }
|
54
|
+
.to raise_error(Errno::EADDRINUSE, 'Address already in use - 21213')
|
53
55
|
server.stop
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
57
59
|
describe FakeFtp::Server, 'files' do
|
58
60
|
let(:file) { FakeFtp::File.new('filename', 34) }
|
59
|
-
let(:server) { FakeFtp::Server.new(
|
61
|
+
let(:server) { FakeFtp::Server.new(21_212) }
|
60
62
|
|
61
|
-
before { server.instance_variable_set(:@
|
63
|
+
before { server.instance_variable_set(:@store, '/pub/filename' => file) }
|
62
64
|
|
63
|
-
it
|
65
|
+
it 'returns filenames from :files' do
|
64
66
|
expect(server.files).to include('filename')
|
65
67
|
end
|
66
68
|
|
67
|
-
it
|
69
|
+
it 'can be accessed with :file' do
|
68
70
|
expect(server.file('filename')).to eql(file)
|
69
71
|
end
|
70
72
|
|
71
|
-
it
|
73
|
+
it 'can reset files' do
|
72
74
|
server.reset
|
73
75
|
expect(server.files).to eql([])
|
74
76
|
end
|
75
77
|
end
|
76
|
-
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,102 @@
|
|
1
|
-
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__), '**','*')
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
require 'bundler/setup'
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
7
4
|
|
5
|
+
require 'simplecov'
|
8
6
|
require 'rspec'
|
9
|
-
require 'fake_ftp'
|
10
|
-
|
11
|
-
RSpec.configure do |
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
7
|
+
require 'fake_ftp'
|
8
|
+
|
9
|
+
RSpec.configure do |c|
|
10
|
+
c.filter_run_excluding(
|
11
|
+
functional: ENV['FUNCTIONAL_SPECS'] != '1',
|
12
|
+
integration: ENV['INTEGRATION_SPECS'] != '1'
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
module SpecHelper
|
17
|
+
def gets_with_timeout(client, timeout: 5, endwith: "\r\n", chunk: 1024)
|
18
|
+
outer_caller = caller(0..1).last.to_s
|
19
|
+
start = Time.now
|
20
|
+
buf = ''
|
21
|
+
loop do
|
22
|
+
if Time.now - start >= timeout
|
23
|
+
raise Timeout::Error, "client=#{client} timeout=#{timeout}s " \
|
24
|
+
"buf=#{buf.inspect} caller=#{outer_caller.inspect}"
|
25
|
+
end
|
26
|
+
bytes = client.read_nonblock(chunk, exception: false)
|
27
|
+
return buf if bytes.nil?
|
28
|
+
buf += bytes unless bytes == :wait_readable
|
29
|
+
return buf if buf.end_with?(endwith)
|
30
|
+
end
|
31
|
+
buf
|
32
|
+
end
|
33
|
+
|
34
|
+
module_function :gets_with_timeout
|
35
|
+
|
36
|
+
def local_addr_bits(port)
|
37
|
+
[
|
38
|
+
127, 0, 0, 1,
|
39
|
+
port / 256,
|
40
|
+
port % 256
|
41
|
+
].map(&:to_s).join(',')
|
42
|
+
end
|
43
|
+
|
44
|
+
module_function :local_addr_bits
|
45
|
+
|
46
|
+
def statline(ftp_file)
|
47
|
+
%W[
|
48
|
+
-rw-r--r--
|
49
|
+
1
|
50
|
+
owner
|
51
|
+
group
|
52
|
+
10
|
53
|
+
#{ftp_file.created.strftime('%b %d %H:%M')}
|
54
|
+
#{ftp_file.name}
|
55
|
+
].join("\t")
|
56
|
+
end
|
57
|
+
|
58
|
+
module_function :statline
|
59
|
+
|
60
|
+
class FakeDataServer
|
61
|
+
def initialize(port)
|
62
|
+
@port = port
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :port
|
66
|
+
|
67
|
+
def addr_bits
|
68
|
+
::SpecHelper.local_addr_bits(port)
|
69
|
+
end
|
70
|
+
|
71
|
+
def start
|
72
|
+
server
|
73
|
+
end
|
74
|
+
|
75
|
+
def stop
|
76
|
+
server.close
|
77
|
+
end
|
78
|
+
|
79
|
+
def handler_sock
|
80
|
+
@handler_sock ||= wait_for_handler_sock
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def wait_for_handler_sock
|
86
|
+
sock = nil
|
87
|
+
|
88
|
+
while sock.nil? || sock == :wait_readable
|
89
|
+
sleep 0.01
|
90
|
+
sock = server.accept_nonblock(exception: false)
|
91
|
+
end
|
92
|
+
|
93
|
+
sock
|
94
|
+
end
|
95
|
+
|
96
|
+
def server
|
97
|
+
@server ||= TCPServer.new('127.0.0.1', port).tap do |srv|
|
98
|
+
srv.sync = true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
18
102
|
end
|