ferver 1.3.0 → 1.3.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.
- 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
|