dassets 0.14.2 → 0.15.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 +7 -7
- data/Gemfile +5 -1
- data/README.md +15 -17
- data/dassets.gemspec +14 -9
- data/lib/dassets.rb +51 -13
- data/lib/dassets/asset_file.rb +27 -24
- data/lib/dassets/cache.rb +27 -33
- data/lib/dassets/config.rb +55 -50
- data/lib/dassets/engine.rb +11 -23
- data/lib/dassets/file_store.rb +27 -27
- data/lib/dassets/server.rb +27 -27
- data/lib/dassets/server/request.rb +44 -41
- data/lib/dassets/server/response.rb +101 -80
- data/lib/dassets/source.rb +15 -9
- data/lib/dassets/source_file.rb +103 -82
- data/lib/dassets/source_proxy.rb +36 -20
- data/lib/dassets/version.rb +3 -1
- data/test/helper.rb +31 -25
- data/test/support/app.rb +5 -5
- data/test/support/empty/{.gitkeep → .keep} +0 -0
- data/test/support/factory.rb +3 -2
- data/test/support/{public/nested/file3-d41d8cd98f00b204e9800998ecf8427e.txt → linked_source_files/linked_file.txt} +0 -0
- data/test/support/source_files/linked +1 -0
- data/test/support/source_files/linked_file2.txt +1 -0
- data/test/system/rack_tests.rb +65 -61
- data/test/unit/asset_file_tests.rb +69 -61
- data/test/unit/cache_tests.rb +15 -34
- data/test/unit/config_tests.rb +59 -52
- data/test/unit/dassets_tests.rb +31 -24
- data/test/unit/engine_tests.rb +9 -43
- data/test/unit/file_store_tests.rb +44 -31
- data/test/unit/server/request_tests.rb +57 -59
- data/test/unit/server/response_tests.rb +82 -82
- data/test/unit/server_tests.rb +5 -9
- data/test/unit/source_file_tests.rb +80 -73
- data/test/unit/source_proxy_tests.rb +84 -90
- data/test/unit/source_tests.rb +66 -50
- data/tmp/.gitkeep +0 -0
- metadata +92 -72
- data/.gitignore +0 -19
- data/test/support/public/file2-9bbe1047cffbb590f59e0e5aeff46ae4.txt +0 -1
- data/test/support/public/grumpy_cat-b0d1f399a916f7a25c4c0f693c619013.jpg +0 -0
- data/test/support/public/nested/a-thing.txt-7413d18f2eba9c695a880aff67fde135.no-use +0 -4
@@ -1,106 +1,104 @@
|
|
1
|
-
|
2
|
-
require 'dassets/server/request'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
3
|
+
require "assert"
|
4
|
+
require "dassets/server/request"
|
5
5
|
|
6
|
-
|
6
|
+
require "dassets/asset_file"
|
7
7
|
|
8
|
+
class Dassets::Server::Request
|
8
9
|
class UnitTests < Assert::Context
|
9
10
|
desc "Dassets::Server::Request"
|
11
|
+
subject{ @req }
|
12
|
+
|
10
13
|
setup do
|
11
|
-
@path =
|
12
|
-
@req = file_request(
|
14
|
+
@path = "/file1-daa05c683a4913b268653f7a7e36a5b4.txt"
|
15
|
+
@req = file_request("GET", @path)
|
13
16
|
end
|
14
|
-
subject{ @req }
|
15
17
|
|
16
18
|
should have_imeths :dassets_base_url
|
17
19
|
should have_imeths :for_asset_file?, :asset_path, :asset_file
|
18
20
|
|
19
|
-
should "know its
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
assert_equal @path, subject.path_info
|
25
|
-
end
|
26
|
-
|
27
|
-
should "know its asset_path" do
|
28
|
-
assert_equal 'file1.txt', subject.asset_path
|
29
|
-
end
|
30
|
-
|
31
|
-
should "know its asset_file" do
|
32
|
-
assert_equal Dassets['file1.txt'], subject.asset_file
|
21
|
+
should "know its attributes" do
|
22
|
+
assert_that(subject.dassets_base_url).equals(Dassets.config.base_url.to_s)
|
23
|
+
assert_that(subject.path_info).equals(@path)
|
24
|
+
assert_that(subject.asset_path).equals("file1.txt")
|
25
|
+
assert_that(subject.asset_file).equals(Dassets["file1.txt"])
|
33
26
|
end
|
34
27
|
|
35
28
|
should "know if it is for an asset file" do
|
36
29
|
# find nested path with matching fingerprint
|
37
|
-
req =
|
38
|
-
|
30
|
+
req =
|
31
|
+
file_request(
|
32
|
+
"GET",
|
33
|
+
"/nested/file3-d41d8cd98f00b204e9800998ecf8427e.txt",
|
34
|
+
)
|
35
|
+
assert_that(req.for_asset_file?).is_true
|
39
36
|
|
40
37
|
# find not nested path with matching fingerprint
|
41
|
-
req = file_request(
|
42
|
-
|
43
|
-
|
44
|
-
# find even if fingerprint is *not* matching - just need to have any
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
38
|
+
req = file_request("HEAD", "/file1-daa05c683a4913b268653f7a7e36a5b4.txt")
|
39
|
+
assert_that(req.for_asset_file?).is_true
|
40
|
+
|
41
|
+
# find even if fingerprint is *not* matching - just need to have any
|
42
|
+
# fingerprint
|
43
|
+
req = file_request("GET", "/file1-d41d8cd98f00b204e9800998ecf8427e.txt")
|
44
|
+
assert_that(req.for_asset_file?).is_true
|
45
|
+
|
46
|
+
# not find an invalid fingerprint
|
47
|
+
req = file_request("GET", "/file1-abc123.txt")
|
48
|
+
assert_that(req.for_asset_file?).is_false
|
49
|
+
|
50
|
+
# not find a missing fingerprint
|
51
|
+
req = file_request("HEAD", "/file1.txt")
|
52
|
+
assert_that(req.for_asset_file?).is_false
|
53
|
+
|
54
|
+
# not find an unknown file with a missing fingerprint
|
55
|
+
req = file_request("GET", "/some-file.txt")
|
56
|
+
assert_that(req.for_asset_file?).is_false
|
57
|
+
|
58
|
+
# not find an unknown file with a valid fingerprint
|
59
|
+
req =
|
60
|
+
file_request("GET", "/some-file-daa05c683a4913b268653f7a7e36a5b4.txt")
|
61
|
+
assert_that(req.for_asset_file?).is_false
|
63
62
|
end
|
64
63
|
|
65
|
-
should "return an
|
66
|
-
req = file_request(
|
64
|
+
should "return an empty path and file if request not for an asset file" do
|
65
|
+
req = file_request("GET", "/some-file.txt")
|
67
66
|
|
68
|
-
|
69
|
-
|
67
|
+
assert_that(req.asset_path).equals("")
|
68
|
+
assert_that(req.asset_file).equals(Dassets::AssetFile.new(""))
|
70
69
|
end
|
71
70
|
|
72
|
-
|
71
|
+
private
|
73
72
|
|
74
73
|
def file_request(method, path_info)
|
75
|
-
require 'dassets/server/request'
|
76
74
|
Dassets::Server::Request.new({
|
77
|
-
|
78
|
-
|
75
|
+
"REQUEST_METHOD" => method,
|
76
|
+
"PATH_INFO" => path_info,
|
79
77
|
})
|
80
78
|
end
|
81
|
-
|
82
79
|
end
|
83
80
|
|
84
81
|
class BaseUrlTests < UnitTests
|
85
82
|
desc "when a base url is configured"
|
83
|
+
|
86
84
|
setup do
|
87
85
|
@orig_base_url = Dassets.config.base_url
|
88
86
|
@new_base_url = Factory.url
|
89
87
|
Dassets.config.base_url(@new_base_url)
|
90
88
|
end
|
89
|
+
|
91
90
|
teardown do
|
92
91
|
Dassets.config.set_base_url(@orig_base_url)
|
93
92
|
end
|
94
93
|
|
95
94
|
should "have the same base url as is configured" do
|
96
|
-
|
95
|
+
assert_that(subject.dassets_base_url).equals(@new_base_url.to_s)
|
97
96
|
end
|
98
97
|
|
99
98
|
should "remove the configured base url from the path info" do
|
100
|
-
|
101
|
-
|
99
|
+
assert_that(file_request("GET", @path).path_info).equals(@path)
|
100
|
+
assert_that(file_request("GET", "#{@new_base_url}#{@path}").path_info)
|
101
|
+
.equals(@path)
|
102
102
|
end
|
103
|
-
|
104
103
|
end
|
105
|
-
|
106
104
|
end
|
@@ -1,77 +1,80 @@
|
|
1
|
-
|
2
|
-
require 'dassets/server/response'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "assert"
|
4
|
+
require "dassets/server/response"
|
6
5
|
|
7
|
-
|
6
|
+
require "rack/utils"
|
7
|
+
require "dassets/asset_file"
|
8
8
|
|
9
|
+
class Dassets::Server::Response
|
9
10
|
class UnitTests < Assert::Context
|
10
11
|
desc "Dassets::Server::Response"
|
12
|
+
subject{ @response }
|
13
|
+
|
11
14
|
setup do
|
12
|
-
@env
|
13
|
-
@asset_file = Dassets[
|
15
|
+
@env = {}
|
16
|
+
@asset_file = Dassets["file1.txt"]
|
14
17
|
|
15
18
|
@response = Dassets::Server::Response.new(@env, @asset_file)
|
16
19
|
end
|
17
|
-
subject{ @response }
|
18
20
|
|
19
21
|
should have_readers :asset_file, :status, :headers, :body
|
20
22
|
should have_imeths :to_rack
|
21
23
|
|
22
24
|
should "handle not modified files" do
|
23
|
-
env = {
|
25
|
+
env = { "HTTP_IF_MODIFIED_SINCE" => @asset_file.mtime }
|
24
26
|
resp = Dassets::Server::Response.new(env, @asset_file)
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
exp_headers = Rack::Utils::HeaderHash.new('Last-Modified' => @asset_file.mtime.to_s)
|
30
|
-
assert_equal exp_headers, resp.headers
|
28
|
+
assert_that(resp.status).equals(304)
|
29
|
+
assert_that(resp.body).equals([])
|
31
30
|
|
32
|
-
|
31
|
+
exp_headers =
|
32
|
+
Rack::Utils::HeaderHash.new("Last-Modified" => @asset_file.mtime.to_s)
|
33
|
+
assert_that(resp.headers).equals(exp_headers)
|
34
|
+
assert_that(resp.to_rack).equals([304, exp_headers.to_hash, []])
|
33
35
|
end
|
34
36
|
|
35
37
|
should "handle found files" do
|
36
38
|
resp = Dassets::Server::Response.new(@env, @asset_file)
|
37
39
|
|
38
|
-
|
40
|
+
assert_that(resp.status).equals(200)
|
39
41
|
|
40
42
|
exp_body = Body.new(@env, @asset_file)
|
41
|
-
|
43
|
+
assert_that(resp.body).equals(exp_body)
|
42
44
|
|
43
|
-
exp_headers =
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
exp_headers =
|
46
|
+
@asset_file.response_headers.merge({
|
47
|
+
"Content-Type" => "text/plain",
|
48
|
+
"Content-Length" => @asset_file.size.to_s,
|
49
|
+
"Last-Modified" => @asset_file.mtime.to_s,
|
50
|
+
})
|
51
|
+
assert_that(resp.headers).equals(exp_headers)
|
49
52
|
|
50
|
-
|
53
|
+
assert_that(resp.to_rack).equals([200, exp_headers, exp_body])
|
51
54
|
end
|
52
55
|
|
53
56
|
should "have an empty body for found files with a HEAD request" do
|
54
|
-
env = {
|
57
|
+
env = { "REQUEST_METHOD" => "HEAD" }
|
55
58
|
resp = Dassets::Server::Response.new(env, @asset_file)
|
56
59
|
|
57
|
-
|
58
|
-
|
60
|
+
assert_that(resp.status).equals(200)
|
61
|
+
assert_that(resp.body).equals([])
|
59
62
|
end
|
60
63
|
|
61
64
|
should "handle not found files" do
|
62
|
-
af = Dassets
|
65
|
+
af = Dassets.asset_file("not-found-file.txt")
|
63
66
|
resp = Dassets::Server::Response.new(@env, af)
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
assert_that(resp.status).equals(404)
|
69
|
+
assert_that(resp.body).equals(["Not Found"])
|
70
|
+
assert_that(resp.headers).equals(Rack::Utils::HeaderHash.new)
|
71
|
+
assert_that(resp.to_rack).equals([404, {}, ["Not Found"]])
|
69
72
|
end
|
70
|
-
|
71
73
|
end
|
72
74
|
|
73
75
|
class PartialContentTests < UnitTests
|
74
76
|
desc "for a partial content request"
|
77
|
+
|
75
78
|
setup do
|
76
79
|
@body = Body.new(@env, @asset_file)
|
77
80
|
Assert.stub(Body, :new).with(@env, @asset_file){ @body }
|
@@ -84,55 +87,54 @@ class Dassets::Server::Response
|
|
84
87
|
end
|
85
88
|
|
86
89
|
should "be a partial content response" do
|
87
|
-
|
90
|
+
assert_that(subject.status).equals(206)
|
88
91
|
|
89
|
-
|
90
|
-
|
92
|
+
assert_that(subject.headers).includes("Content-Range")
|
93
|
+
assert_that(subject.headers["Content-Range"]).equals(@body.content_range)
|
91
94
|
end
|
92
|
-
|
93
95
|
end
|
94
96
|
|
95
97
|
class BodyTests < UnitTests
|
96
98
|
desc "Body"
|
99
|
+
subject{ @body }
|
100
|
+
|
97
101
|
setup do
|
98
102
|
@body = Body.new(@env, @asset_file)
|
99
103
|
end
|
100
|
-
subject{ @body }
|
101
104
|
|
102
105
|
should have_readers :asset_file, :size, :content_range
|
103
106
|
should have_imeths :partial?, :range_begin, :range_end
|
104
107
|
should have_imeths :each
|
105
108
|
|
106
109
|
should "know its chunk size" do
|
107
|
-
|
110
|
+
assert_that(Body::CHUNK_SIZE).equals(8192)
|
108
111
|
end
|
109
112
|
|
110
113
|
should "know its asset file" do
|
111
|
-
|
114
|
+
assert_that(subject.asset_file).equals(@asset_file)
|
112
115
|
end
|
113
116
|
|
114
117
|
should "know if it is equal to another body" do
|
115
118
|
same_af_same_range = Body.new(@env, @asset_file)
|
116
119
|
Assert.stub(same_af_same_range, :range_begin){ subject.range_begin }
|
117
120
|
Assert.stub(same_af_same_range, :range_end){ subject.range_end }
|
118
|
-
|
121
|
+
assert_that(subject).equals(same_af_same_range)
|
119
122
|
|
120
|
-
other_af_same_range = Body.new(@env, Dassets[
|
123
|
+
other_af_same_range = Body.new(@env, Dassets["file2.txt"])
|
121
124
|
Assert.stub(other_af_same_range, :range_begin){ subject.range_begin }
|
122
125
|
Assert.stub(other_af_same_range, :range_end){ subject.range_end }
|
123
|
-
|
126
|
+
assert_that(subject).does_not_equal(other_af_same_range)
|
124
127
|
|
125
128
|
same_af_other_range = Body.new(@env, @asset_file)
|
126
129
|
|
127
130
|
Assert.stub(same_af_other_range, :range_begin){ Factory.integer }
|
128
131
|
Assert.stub(same_af_other_range, :range_end){ subject.range_end }
|
129
|
-
|
132
|
+
assert_that(subject).does_not_equal(same_af_other_range)
|
130
133
|
|
131
134
|
Assert.stub(same_af_other_range, :range_begin){ subject.range_begin }
|
132
135
|
Assert.stub(same_af_other_range, :range_end){ Factory.integer }
|
133
|
-
|
136
|
+
assert_that(subject).does_not_equal(same_af_other_range)
|
134
137
|
end
|
135
|
-
|
136
138
|
end
|
137
139
|
|
138
140
|
class BodyIOTests < BodyTests
|
@@ -140,132 +142,130 @@ class Dassets::Server::Response
|
|
140
142
|
@min_num_chunks = 3
|
141
143
|
@num_chunks = @min_num_chunks + Factory.integer(3)
|
142
144
|
|
143
|
-
content =
|
145
|
+
content = "a" * (@num_chunks * Body::CHUNK_SIZE)
|
144
146
|
Assert.stub(@asset_file, :content){ content }
|
145
147
|
end
|
146
|
-
|
147
148
|
end
|
148
149
|
|
149
150
|
class NonPartialBodyTests < BodyIOTests
|
150
151
|
desc "for non/multi/invalid partial content requests"
|
152
|
+
|
151
153
|
setup do
|
152
|
-
range = [nil,
|
153
|
-
env = range.nil? ? {} : {
|
154
|
+
range = [nil, "bytes=", "bytes=0-1,2-3", "bytes=3-2", "bytes=abc"].sample
|
155
|
+
env = range.nil? ? {} : { "HTTP_RANGE" => range }
|
154
156
|
@body = Body.new(env, @asset_file)
|
155
157
|
end
|
156
158
|
|
157
159
|
should "not be partial" do
|
158
|
-
|
160
|
+
assert_that(subject.partial?).is_false
|
159
161
|
end
|
160
162
|
|
161
163
|
should "be the full content size" do
|
162
|
-
|
164
|
+
assert_that(subject.size).equals(@asset_file.size)
|
163
165
|
end
|
164
166
|
|
165
167
|
should "have no content range" do
|
166
|
-
|
168
|
+
assert_that(subject.content_range).is_nil
|
167
169
|
end
|
168
170
|
|
169
171
|
should "have the full content size as its range" do
|
170
|
-
|
171
|
-
|
172
|
+
assert_that(subject.range_begin).equals(0)
|
173
|
+
assert_that(subject.range_end).equals(subject.size - 1)
|
172
174
|
end
|
173
175
|
|
174
176
|
should "chunk the full content when iterated" do
|
175
177
|
chunks = []
|
176
178
|
subject.each{ |chunk| chunks << chunk }
|
177
179
|
|
178
|
-
|
179
|
-
|
180
|
-
|
180
|
+
assert_that(chunks.size).equals(@num_chunks)
|
181
|
+
assert_that(chunks.first.size).equals(subject.class::CHUNK_SIZE)
|
182
|
+
assert_that(chunks.join("")).equals(@asset_file.content)
|
181
183
|
end
|
182
|
-
|
183
184
|
end
|
184
185
|
|
185
186
|
class PartialBodySetupTests < BodyIOTests
|
186
187
|
desc "for a partial content request"
|
188
|
+
|
187
189
|
setup do
|
188
190
|
@start_chunk = Factory.boolean ? 0 : 1
|
189
191
|
@partial_begin = @start_chunk * Body::CHUNK_SIZE
|
190
192
|
@partial_chunks = @num_chunks - Factory.integer(@min_num_chunks)
|
191
193
|
@partial_size = @partial_chunks * Body::CHUNK_SIZE
|
192
|
-
@partial_end = @partial_begin + (@partial_size-1)
|
194
|
+
@partial_end = @partial_begin + (@partial_size - 1)
|
193
195
|
|
194
|
-
@env = {
|
196
|
+
@env = { "HTTP_RANGE" => "bytes=#{@partial_begin}-#{@partial_end}" }
|
195
197
|
end
|
196
|
-
|
197
198
|
end
|
198
199
|
|
199
200
|
class PartialBodyTests < PartialBodySetupTests
|
201
|
+
subject{ @body }
|
202
|
+
|
200
203
|
setup do
|
201
204
|
@body = Body.new(@env, @asset_file)
|
202
205
|
end
|
203
|
-
subject{ @body }
|
204
206
|
|
205
207
|
should "be partial" do
|
206
|
-
|
208
|
+
assert_that(subject.partial?).is_true
|
207
209
|
end
|
208
210
|
|
209
211
|
should "be the specified partial size" do
|
210
|
-
|
212
|
+
assert_that(subject.size).equals(@partial_size)
|
211
213
|
end
|
212
214
|
|
213
215
|
should "know its content range" do
|
214
216
|
exp = "bytes #{@partial_begin}-#{@partial_end}/#{@asset_file.size}"
|
215
|
-
|
217
|
+
assert_that(subject.content_range).equals(exp)
|
216
218
|
end
|
217
219
|
|
218
220
|
should "have the know its range" do
|
219
|
-
|
220
|
-
|
221
|
+
assert_that(subject.range_begin).equals(@partial_begin)
|
222
|
+
assert_that(subject.range_end).equals(@partial_end)
|
221
223
|
end
|
222
224
|
|
223
225
|
should "chunk the range when iterated" do
|
224
226
|
chunks = []
|
225
227
|
subject.each{ |chunk| chunks << chunk }
|
226
228
|
|
227
|
-
|
228
|
-
|
229
|
+
assert_that(chunks.size).equals(@partial_chunks)
|
230
|
+
assert_that(chunks.first.size).equals(subject.class::CHUNK_SIZE)
|
229
231
|
|
230
232
|
exp = @asset_file.content[@partial_begin..@partial_end]
|
231
|
-
|
233
|
+
assert_that(chunks.join("")).equals(exp)
|
232
234
|
end
|
233
|
-
|
234
235
|
end
|
235
236
|
|
236
237
|
class LegacyRackTests < PartialBodySetupTests
|
237
238
|
desc "when using a legacy version of rack that can't interpret byte ranges"
|
239
|
+
|
238
240
|
setup do
|
239
241
|
Assert.stub(Rack::Utils, :respond_to?).with(:byte_ranges){ false }
|
240
242
|
@body = Body.new(@env, @asset_file)
|
241
243
|
end
|
242
244
|
|
243
245
|
should "not be partial" do
|
244
|
-
|
246
|
+
assert_that(subject.partial?).is_false
|
245
247
|
end
|
246
248
|
|
247
249
|
should "be the full content size" do
|
248
|
-
|
250
|
+
assert_that(subject.size).equals(@asset_file.size)
|
249
251
|
end
|
250
252
|
|
251
253
|
should "have no content range" do
|
252
|
-
|
254
|
+
assert_that(subject.content_range).is_nil
|
253
255
|
end
|
254
256
|
|
255
257
|
should "have the full content size as its range" do
|
256
|
-
|
257
|
-
|
258
|
+
assert_that(subject.range_begin).equals(0)
|
259
|
+
assert_that(subject.range_end).equals(subject.size - 1)
|
258
260
|
end
|
259
261
|
|
260
262
|
should "chunk the full content when iterated" do
|
261
263
|
chunks = []
|
262
264
|
subject.each{ |chunk| chunks << chunk }
|
263
265
|
|
264
|
-
|
265
|
-
|
266
|
-
|
266
|
+
assert_that(chunks.size).equals(@num_chunks)
|
267
|
+
assert_that(chunks.first.size).equals(subject.class::CHUNK_SIZE)
|
268
|
+
assert_that(chunks.join("")).equals(@asset_file.content)
|
267
269
|
end
|
268
|
-
|
269
270
|
end
|
270
|
-
|
271
271
|
end
|