ferver 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +2 -1
- data/.rubocop.yml +13 -0
- data/.ruby-version +1 -1
- data/.travis.yml +6 -1
- data/Gemfile +2 -1
- data/README.md +11 -1
- data/Rakefile +1 -0
- data/bin/ferver +20 -9
- data/ferver.gemspec +22 -20
- data/lib/ferver.rb +9 -11
- data/lib/ferver/app.rb +5 -4
- data/lib/ferver/configuration.rb +18 -9
- data/lib/ferver/controller.rb +25 -30
- data/lib/ferver/errors.rb +5 -0
- data/lib/ferver/ferver_directory.rb +43 -0
- data/lib/ferver/file_list.rb +10 -34
- data/lib/ferver/found_file.rb +2 -1
- data/lib/ferver/version.rb +2 -1
- data/spec/configuration_spec.rb +16 -10
- data/spec/ferver_directory_spec.rb +78 -0
- data/spec/ferver_spec.rb +62 -97
- data/spec/file_list_spec.rb +40 -112
- data/spec/found_file_spec.rb +54 -0
- data/spec/spec_helper.rb +44 -29
- metadata +41 -24
- data/lib/ferver/directory_not_found_error.rb +0 -3
- data/lib/ferver/file_id_request.rb +0 -32
- data/spec/file_id_request_spec.rb +0 -65
data/lib/ferver/file_list.rb
CHANGED
@@ -1,52 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# A representation of Ferver's file list
|
4
|
-
#
|
1
|
+
# frozen_string_literal: true
|
5
2
|
module Ferver
|
3
|
+
# A representation of Ferver's file list
|
6
4
|
class FileList
|
7
5
|
include Enumerable
|
8
6
|
|
9
|
-
# Create a new instance with
|
7
|
+
# Create a new instance with given directory
|
10
8
|
#
|
11
|
-
def initialize(
|
12
|
-
|
13
|
-
fail DirectoryNotFoundError unless Dir.exist?(path)
|
14
|
-
|
15
|
-
@configured_file_path = File.expand_path(path)
|
16
|
-
@files = find_files.sort_by! { |f| f.name.downcase }
|
9
|
+
def initialize(files)
|
10
|
+
@files = files.sort_by { |f| f.name.downcase }
|
17
11
|
end
|
18
12
|
|
19
13
|
def each(&block)
|
20
|
-
files.each(&block)
|
14
|
+
@files.each(&block)
|
21
15
|
end
|
22
16
|
|
23
17
|
def size
|
24
|
-
files.size
|
18
|
+
@files.size
|
25
19
|
end
|
26
20
|
|
27
|
-
#
|
28
|
-
# An id out of range with raise
|
21
|
+
# Fetch a file by its index
|
22
|
+
# An id out of range with raise FileNotFoundError
|
29
23
|
#
|
30
24
|
def file_by_id(id)
|
31
|
-
files.
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_reader :configured_file_path, :files
|
37
|
-
|
38
|
-
# Iterate through files in specified dir for files
|
39
|
-
#
|
40
|
-
def find_files
|
41
|
-
[].tap do |results|
|
42
|
-
Dir.foreach(configured_file_path) do |file_name|
|
43
|
-
next if file_name == '.' || file_name == '..'
|
44
|
-
next if file_name =~ /^\./ && !Ferver.configuration.serve_hidden?
|
45
|
-
|
46
|
-
found_file = FoundFile.new(configured_file_path, file_name)
|
47
|
-
results << found_file if found_file.valid?
|
48
|
-
end
|
49
|
-
end
|
25
|
+
@files.at(id) || raise(FileNotFoundError, "File id=#{id} not found")
|
50
26
|
end
|
51
27
|
end
|
52
28
|
end
|
data/lib/ferver/found_file.rb
CHANGED
data/lib/ferver/version.rb
CHANGED
data/spec/configuration_spec.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Ferver::Configuration do
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.describe Ferver::Configuration do
|
4
3
|
subject { described_class.new }
|
5
4
|
|
6
|
-
describe
|
7
|
-
context
|
8
|
-
it
|
9
|
-
expect(subject.directory_path).to eq(
|
5
|
+
describe "configured directory path" do
|
6
|
+
context "with no path set" do
|
7
|
+
it "should return default path" do
|
8
|
+
expect(subject.directory_path).to eq("./")
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
|
-
context
|
14
|
-
let(:path) {
|
12
|
+
context "when directory is set" do
|
13
|
+
let(:path) { "/foo/bar" }
|
15
14
|
|
16
|
-
it
|
15
|
+
it "should return default path" do
|
17
16
|
subject.directory_path = path
|
18
17
|
|
19
18
|
expect(subject.directory_path).to eq(path)
|
@@ -36,4 +35,11 @@ describe Ferver::Configuration do
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
38
|
+
|
39
|
+
describe "#directory" do
|
40
|
+
it "is a FerverDirectory with configuration" do
|
41
|
+
expect(Ferver::FerverDirectory).to receive(:new).with(subject).and_call_original
|
42
|
+
expect(subject.directory).to be_instance_of Ferver::FerverDirectory
|
43
|
+
end
|
44
|
+
end
|
39
45
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.describe Ferver::FerverDirectory do
|
3
|
+
subject { described_class.new config }
|
4
|
+
|
5
|
+
let(:config) { double("Ferver::Configuration", directory_path: path, serve_hidden?: serve_hidden) }
|
6
|
+
let(:path) { "/dev" }
|
7
|
+
let(:serve_hidden) { true }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(Dir).to receive(:exist?).and_return true
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "assertions" do
|
14
|
+
context "when path is empty" do
|
15
|
+
let(:path) { "" }
|
16
|
+
|
17
|
+
it "raises error" do
|
18
|
+
expect { described_class.new config }.to raise_error(ArgumentError, "No path is specified")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when directory does not exist" do
|
23
|
+
before do
|
24
|
+
allow(Dir).to receive(:exist?).and_return false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises error" do
|
28
|
+
expect { described_class.new config }.to raise_error(Ferver::DirectoryNotFoundError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#path" do
|
34
|
+
let(:path) { "/dev/random" }
|
35
|
+
|
36
|
+
it "is the path from config" do
|
37
|
+
expect(subject.path).to eq "/dev/random"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#full_path" do
|
42
|
+
let(:path) { "./" }
|
43
|
+
|
44
|
+
it "is the full path to directory" do
|
45
|
+
expect(File).to receive(:expand_path).with("./").and_return("/my/home")
|
46
|
+
expect(subject.full_path).to eq "/my/home"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#found_files" do
|
51
|
+
before(:each) do
|
52
|
+
allow(Dir).to receive(:foreach)
|
53
|
+
.and_yield(".")
|
54
|
+
.and_yield("..")
|
55
|
+
.and_yield("zero file")
|
56
|
+
.and_yield("normal_file.txt")
|
57
|
+
.and_yield(".hidden")
|
58
|
+
allow(File).to receive(:file?).at_most(3).times.and_return(true, true, true)
|
59
|
+
allow(File).to receive(:zero?).at_most(3).times.and_return(true, false, false)
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when configured to serve all files" do
|
63
|
+
let(:serve_hidden) { true }
|
64
|
+
|
65
|
+
it "returns list of files matched" do
|
66
|
+
expect(subject.found_files.map(&:name)).to eq ["normal_file.txt", ".hidden"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when configured not to serve hidden files" do
|
71
|
+
let(:serve_hidden) { false }
|
72
|
+
|
73
|
+
it "returns list of files matched" do
|
74
|
+
expect(subject.found_files.map(&:name)).to eq ["normal_file.txt"]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/ferver_spec.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.describe "ferver" do
|
3
|
+
let(:ferver_directory) { double("Ferver::FerverDirectory", path: "/", full_path: "/path/to/files", found_files: []) }
|
4
|
+
before do
|
5
|
+
Ferver.configure do |conf|
|
6
|
+
conf.directory = ferver_directory
|
7
|
+
end
|
8
|
+
end
|
5
9
|
|
6
|
-
context
|
10
|
+
context "given a request to the server root" do
|
7
11
|
before do
|
8
|
-
get
|
12
|
+
get "/"
|
9
13
|
end
|
10
14
|
|
11
|
-
it
|
15
|
+
it "should return redirect" do
|
12
16
|
expect(last_response).to be_redirect
|
13
17
|
end
|
14
18
|
|
15
|
-
it
|
19
|
+
it "should redirect to file list" do
|
16
20
|
follow_redirect!
|
17
21
|
|
18
22
|
expect(last_response).to be_ok
|
@@ -20,130 +24,94 @@ describe 'ferver' do
|
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
23
|
-
describe
|
24
|
-
|
25
|
-
allow(file_list).to receive(:each_with_index)
|
26
|
-
allow(file_list).to receive(:size).and_return(0)
|
27
|
-
end
|
28
|
-
|
29
|
-
context 'when no directory is specified' do
|
30
|
-
it 'will use default directory' do
|
31
|
-
expect(Ferver::FileList).to receive(:new).with('./').and_return(file_list)
|
32
|
-
|
33
|
-
get '/files'
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'when the directory passed via configuration' do
|
27
|
+
describe "configuration error" do
|
28
|
+
context "when directory does not exist" do
|
38
29
|
before do
|
39
|
-
|
40
|
-
conf.directory_path = '/foo'
|
41
|
-
end
|
30
|
+
allow(ferver_directory).to receive(:found_files).and_raise(Ferver::DirectoryNotFoundError)
|
42
31
|
end
|
43
32
|
|
44
|
-
it
|
45
|
-
|
46
|
-
|
47
|
-
get '/files'
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'when directory does not exist' do
|
52
|
-
before do
|
53
|
-
allow(Ferver::FileList).to receive(:new).and_raise(Ferver::DirectoryNotFoundError)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'will return server error status' do
|
57
|
-
get '/files'
|
33
|
+
it "will return server error status" do
|
34
|
+
get "/files"
|
58
35
|
|
59
36
|
expect(last_response.status).to eql 500
|
60
37
|
end
|
61
38
|
end
|
62
39
|
end
|
63
40
|
|
64
|
-
context
|
41
|
+
context "given an empty list of files" do
|
65
42
|
before do
|
66
|
-
allow(
|
67
|
-
allow(file_list).to receive(:size).and_return(0)
|
68
|
-
allow(Ferver::FileList).to receive(:new).and_return(file_list)
|
43
|
+
allow(ferver_directory).to receive(:found_files).and_return(EMPTY_FILE_LIST)
|
69
44
|
end
|
70
45
|
|
71
|
-
context
|
72
|
-
before { get
|
46
|
+
context "when no content-type is requested" do
|
47
|
+
before { get "/files" }
|
73
48
|
|
74
|
-
it
|
49
|
+
it "should return valid response" do
|
75
50
|
expect(last_response).to be_ok
|
76
51
|
end
|
77
52
|
|
78
|
-
it
|
79
|
-
expect(last_response.body).not_to have_tag(
|
80
|
-
expect(last_response.body).to have_tag(
|
53
|
+
it "should contain no file list in response content" do
|
54
|
+
expect(last_response.body).not_to have_tag("li")
|
55
|
+
expect(last_response.body).to have_tag("p", text: /0 files/)
|
81
56
|
end
|
82
57
|
end
|
83
58
|
|
84
|
-
context
|
59
|
+
context "when json content-type is requested" do
|
85
60
|
before do
|
86
|
-
|
87
|
-
|
88
|
-
get '/files', {}, 'HTTP_ACCEPT' => 'application/json'
|
61
|
+
get "/files", {}, "HTTP_ACCEPT" => "application/json"
|
89
62
|
end
|
90
63
|
|
91
|
-
it
|
64
|
+
it "should return valid response" do
|
92
65
|
expect(last_response).to be_ok
|
93
|
-
expect(last_response.content_type).to include(
|
66
|
+
expect(last_response.content_type).to include("application/json")
|
94
67
|
end
|
95
68
|
|
96
|
-
it
|
69
|
+
it "should contain no file list in response content" do
|
97
70
|
list = JSON.parse last_response.body
|
98
71
|
expect(list).to eq(EMPTY_FILE_LIST)
|
99
72
|
end
|
100
73
|
end
|
101
74
|
end
|
102
75
|
|
103
|
-
context
|
104
|
-
let(:file_1) { double(
|
105
|
-
let(:file_2) { double(
|
76
|
+
context "given a list of files" do
|
77
|
+
let(:file_1) { double("file", name: "file1") }
|
78
|
+
let(:file_2) { double("file", name: "file2") }
|
106
79
|
before do
|
107
|
-
allow(
|
108
|
-
allow(file_list).to receive(:size).and_return(2)
|
109
|
-
allow(Ferver::FileList).to receive(:new).and_return(file_list)
|
80
|
+
allow(ferver_directory).to receive(:found_files).and_return([file_1, file_2])
|
110
81
|
end
|
111
82
|
|
112
|
-
describe
|
113
|
-
|
114
|
-
|
115
|
-
before { get '/files' }
|
83
|
+
describe "file list request" do
|
84
|
+
context "when no content-type is requested" do
|
85
|
+
before { get "/files" }
|
116
86
|
|
117
|
-
it
|
87
|
+
it "should return valid response" do
|
118
88
|
expect(last_response).to be_ok
|
119
89
|
end
|
120
90
|
|
121
|
-
it
|
122
|
-
expect(last_response.body).to have_tag(
|
123
|
-
expect(last_response.body).to have_tag(
|
91
|
+
it "should contain no file list in response content" do
|
92
|
+
expect(last_response.body).to have_tag("li", count: 2)
|
93
|
+
expect(last_response.body).to have_tag("p", text: /2 files/)
|
124
94
|
end
|
125
95
|
|
126
|
-
it
|
127
|
-
expect(last_response.body).to have_tag(
|
128
|
-
with_tag(
|
129
|
-
with_tag(
|
96
|
+
it "should list filenames" do
|
97
|
+
expect(last_response.body).to have_tag("li") do
|
98
|
+
with_tag("a", text: "file1")
|
99
|
+
with_tag("a", text: "file2")
|
130
100
|
end
|
131
101
|
end
|
132
102
|
end
|
133
103
|
|
134
|
-
context
|
104
|
+
context "when json content-type is requested" do
|
135
105
|
before do
|
136
|
-
|
137
|
-
|
138
|
-
get '/files', {}, 'HTTP_ACCEPT' => 'application/json'
|
106
|
+
get "/files", {}, "HTTP_ACCEPT" => "application/json"
|
139
107
|
end
|
140
108
|
|
141
|
-
it
|
109
|
+
it "should return valid response" do
|
142
110
|
expect(last_response).to be_ok
|
143
|
-
expect(last_response.content_type).to include(
|
111
|
+
expect(last_response.content_type).to include("application/json")
|
144
112
|
end
|
145
113
|
|
146
|
-
it
|
114
|
+
it "should contain no file list in response content" do
|
147
115
|
list = JSON.parse last_response.body
|
148
116
|
expect(list.count).to eq(2)
|
149
117
|
expect(list).to match_array([file_1.name, file_2.name])
|
@@ -151,38 +119,35 @@ describe 'ferver' do
|
|
151
119
|
end
|
152
120
|
end
|
153
121
|
|
154
|
-
describe
|
155
|
-
|
156
|
-
context 'when requesting a file out of range' do
|
122
|
+
describe "downloading a file" do
|
123
|
+
context "when requesting a file out of range" do
|
157
124
|
before do
|
158
|
-
|
159
|
-
get '/files/3'
|
125
|
+
get "/files/3"
|
160
126
|
end
|
161
127
|
|
162
|
-
it
|
128
|
+
it "should return not_found" do
|
163
129
|
expect(last_response).to be_not_found
|
164
130
|
end
|
165
131
|
end
|
166
132
|
|
167
|
-
context
|
168
|
-
before { get
|
133
|
+
context "when requesting invalid file id" do
|
134
|
+
before { get "/files/foo" }
|
169
135
|
|
170
|
-
it
|
136
|
+
it "should return not_found" do
|
171
137
|
expect(last_response).to be_bad_request
|
172
138
|
end
|
173
139
|
end
|
174
140
|
|
175
|
-
context
|
176
|
-
before { get
|
141
|
+
context "when requesting a valid file id" do
|
142
|
+
before { get "/files/0" }
|
177
143
|
|
178
|
-
xit
|
144
|
+
xit "should return ok response" do
|
179
145
|
expect(last_response).to be_ok
|
180
146
|
end
|
181
147
|
|
182
|
-
xit
|
183
|
-
expect(last_response.headers[
|
148
|
+
xit "should return octet-stream content-type" do
|
149
|
+
expect(last_response.headers["Content-Type"]).to eq("application/octet-stream")
|
184
150
|
end
|
185
|
-
|
186
151
|
end
|
187
152
|
end
|
188
153
|
end
|