thingfish 0.5.0.pre20161103181816 → 0.8.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.md +48 -0
- data/{README.rdoc → README.md} +40 -26
- data/Rakefile +4 -88
- data/bin/thingfish +1 -1
- data/lib/strelka/app/metadata.rb +1 -1
- data/lib/strelka/apps.rb +9 -0
- data/lib/strelka/httprequest/metadata.rb +1 -1
- data/lib/thingfish.rb +2 -13
- data/lib/thingfish/behaviors.rb +1 -1
- data/lib/thingfish/datastore.rb +1 -1
- data/lib/thingfish/datastore/memory.rb +1 -1
- data/lib/thingfish/handler.rb +94 -53
- data/lib/thingfish/metastore.rb +1 -1
- data/lib/thingfish/metastore/memory.rb +1 -1
- data/lib/thingfish/mixins.rb +1 -1
- data/lib/thingfish/processor.rb +1 -1
- data/lib/thingfish/processor/sha256.rb +51 -0
- data/lib/thingfish/spechelpers.rb +1 -1
- data/spec/helpers.rb +19 -12
- data/spec/thingfish/datastore/memory_spec.rb +1 -1
- data/spec/thingfish/datastore_spec.rb +1 -1
- data/spec/thingfish/handler_spec.rb +235 -201
- data/spec/thingfish/metastore/memory_spec.rb +1 -1
- data/spec/thingfish/metastore_spec.rb +1 -1
- data/spec/thingfish/mixins_spec.rb +1 -1
- data/spec/thingfish/processor/{mp3_spec.rb → sha256_spec.rb} +10 -11
- data/spec/thingfish/processor_spec.rb +1 -1
- data/spec/thingfish_spec.rb +1 -1
- metadata +61 -141
- metadata.gz.sig +0 -0
- data/History.rdoc +0 -5
- data/Manifest.txt +0 -44
- data/Procfile +0 -4
- data/bin/tfprocessord +0 -6
- data/etc/thingfish.conf.example +0 -26
- data/lib/thingfish/processor/mp3.rb +0 -167
- data/lib/thingfish/processordaemon.rb +0 -16
data/lib/thingfish/metastore.rb
CHANGED
data/lib/thingfish/mixins.rb
CHANGED
data/lib/thingfish/processor.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'digest/sha2'
|
5
|
+
|
6
|
+
require 'thingfish' unless defined?( Thingfish )
|
7
|
+
require 'thingfish/processor' unless defined?( Thingfish::Processor )
|
8
|
+
|
9
|
+
|
10
|
+
# Calculate and store a sha256 checksum for a resource.
|
11
|
+
class Thingfish::Processor::SHA256 < Thingfish::Processor
|
12
|
+
extend Loggability
|
13
|
+
|
14
|
+
# The chunk size to read
|
15
|
+
CHUNK_SIZE = 32 * 1024
|
16
|
+
|
17
|
+
# Loggability API -- log to the :thingfish logger
|
18
|
+
log_to :thingfish
|
19
|
+
|
20
|
+
# The list of handled types
|
21
|
+
handled_types '*/*'
|
22
|
+
|
23
|
+
|
24
|
+
### Synchronous processor API -- generate a checksum during upload.
|
25
|
+
def on_request( request )
|
26
|
+
request.add_metadata( :checksum => self.checksum(request.body) )
|
27
|
+
request.related_resources.each_pair do |io, metadata|
|
28
|
+
metadata[ :checksum ] = self.checksum( io )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
#########
|
34
|
+
protected
|
35
|
+
#########
|
36
|
+
|
37
|
+
### Given an +io+, return a sha256 checksum of it's contents.
|
38
|
+
def checksum( io )
|
39
|
+
digest = Digest::SHA256.new
|
40
|
+
buf = String.new
|
41
|
+
|
42
|
+
while io.read( CHUNK_SIZE, buf )
|
43
|
+
digest.update( buf )
|
44
|
+
end
|
45
|
+
|
46
|
+
io.rewind
|
47
|
+
return digest.hexdigest
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Thingfish::Processor::SHA256
|
51
|
+
|
data/spec/helpers.rb
CHANGED
@@ -42,25 +42,32 @@ Loggability.format_with( :color ) if $stdout.tty?
|
|
42
42
|
|
43
43
|
|
44
44
|
### Mock with RSpec
|
45
|
-
RSpec.configure do |
|
45
|
+
RSpec.configure do |config|
|
46
46
|
include Strelka::Constants
|
47
47
|
include Thingfish::SpecHelpers
|
48
48
|
include Thingfish::SpecHelpers::Constants
|
49
49
|
|
50
|
-
|
51
|
-
c.filter_run :focus
|
52
|
-
c.order = 'random'
|
53
|
-
c.mock_with( :rspec ) do |mock|
|
50
|
+
config.mock_with( :rspec ) do |mock|
|
54
51
|
mock.syntax = :expect
|
55
52
|
end
|
56
53
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
54
|
+
config.disable_monkey_patching!
|
55
|
+
config.example_status_persistence_file_path = "spec/.status"
|
56
|
+
config.filter_run :focus
|
57
|
+
config.filter_run_when_matching :focus
|
58
|
+
config.order = :random
|
59
|
+
config.profile_examples = 5
|
60
|
+
config.run_all_when_everything_filtered = true
|
61
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
62
|
+
# config.warnings = true
|
63
|
+
|
64
|
+
config.include( Loggability::SpecHelpers )
|
65
|
+
config.include( Mongrel2::SpecHelpers )
|
66
|
+
config.include( Mongrel2::Constants )
|
67
|
+
config.include( Mongrel2::Config::DSL )
|
68
|
+
config.include( Strelka::Constants )
|
69
|
+
config.include( Strelka::Testing )
|
70
|
+
config.include( Thingfish::SpecHelpers )
|
64
71
|
end
|
65
72
|
|
66
73
|
# vim: set nosta noet ts=4 sw=4:
|
@@ -7,27 +7,18 @@ require 'thingfish/handler'
|
|
7
7
|
require 'thingfish/processor'
|
8
8
|
|
9
9
|
|
10
|
-
describe Thingfish::Handler do
|
10
|
+
RSpec.describe Thingfish::Handler do
|
11
11
|
|
12
|
-
EVENT_SOCKET_URI = 'tcp://127.0.0.1
|
12
|
+
EVENT_SOCKET_URI = 'tcp://127.0.0.1:*'
|
13
13
|
|
14
14
|
before( :all ) do
|
15
15
|
Thingfish::Handler.configure( :event_socket_uri => EVENT_SOCKET_URI )
|
16
16
|
Thingfish::Handler.install_plugins
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@handler = described_class.new( TEST_APPID, TEST_SEND_SPEC, TEST_RECV_SPEC )
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
after( :each ) do
|
27
|
-
@handler.shutdown
|
28
|
-
end
|
29
|
-
|
30
|
-
# let( :handler ) { described_class.new(TEST_APPID, TEST_SEND_SPEC, TEST_RECV_SPEC) }
|
19
|
+
let( :png_io ) { StringIO.new( TEST_PNG_DATA.dup ) }
|
20
|
+
let( :text_io ) { StringIO.new( TEST_TEXT_DATA.dup ) }
|
21
|
+
let( :handler ) { described_class.new(TEST_APPID, TEST_SEND_SPEC, TEST_RECV_SPEC) }
|
31
22
|
|
32
23
|
|
33
24
|
#
|
@@ -51,7 +42,7 @@ describe Thingfish::Handler do
|
|
51
42
|
|
52
43
|
it 'returns interesting configuration info' do
|
53
44
|
req = factory.get( '/serverinfo', content_type: 'text/plain' )
|
54
|
-
res =
|
45
|
+
res = handler.handle( req )
|
55
46
|
|
56
47
|
expect( res.status_line ).to match( /200 ok/i )
|
57
48
|
expect( res.headers ).to include( 'x-thingfish' )
|
@@ -73,7 +64,7 @@ describe Thingfish::Handler do
|
|
73
64
|
req = factory.post( '/', TEST_TEXT_DATA )
|
74
65
|
req.content_type = 'text/plain'
|
75
66
|
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
76
|
-
res =
|
67
|
+
res = handler.handle( req )
|
77
68
|
|
78
69
|
expect( res.status_line ).to match( /201 created/i )
|
79
70
|
expect( res.headers.location.to_s ).to match( %r:/#{UUID_PATTERN}$: )
|
@@ -100,18 +91,18 @@ describe Thingfish::Handler do
|
|
100
91
|
with( spool_path, 'r', encoding: Encoding::ASCII_8BIT ).
|
101
92
|
and_return( fh )
|
102
93
|
|
103
|
-
start_req = factory.post( '/',
|
94
|
+
start_req = factory.post( '/', '',
|
104
95
|
x_mongrel2_upload_start: spool_path,
|
105
96
|
content_length: upload_size,
|
106
97
|
content_type: 'text/plain' )
|
107
|
-
upload_req = factory.post( '/',
|
98
|
+
upload_req = factory.post( '/', '',
|
108
99
|
x_mongrel2_upload_start: spool_path,
|
109
100
|
x_mongrel2_upload_done: spool_path,
|
110
101
|
content_length: upload_size,
|
111
102
|
content_type: 'text/plain' )
|
112
103
|
|
113
|
-
start_res =
|
114
|
-
upload_res =
|
104
|
+
start_res = handler.dispatch_request( start_req )
|
105
|
+
upload_res = handler.dispatch_request( upload_req )
|
115
106
|
|
116
107
|
expect( start_res ).to be_nil
|
117
108
|
|
@@ -151,7 +142,7 @@ describe Thingfish::Handler do
|
|
151
142
|
req = factory.post( '/', TEST_TEXT_DATA )
|
152
143
|
req.content_type = 'text/plain'
|
153
144
|
|
154
|
-
res =
|
145
|
+
res = handler.handle( req )
|
155
146
|
res.body.rewind
|
156
147
|
expect( res.status ).to be( HTTP::BAD_REQUEST )
|
157
148
|
expect( res.body.read ).to match( /missing operational attribute/i )
|
@@ -166,60 +157,60 @@ describe Thingfish::Handler do
|
|
166
157
|
}
|
167
158
|
req = factory.post( '/', TEST_TEXT_DATA, headers )
|
168
159
|
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
169
|
-
res =
|
160
|
+
res = handler.handle( req )
|
170
161
|
|
171
162
|
expect( res.status_line ).to match( /201 created/i )
|
172
163
|
expect( res.headers.location.to_s ).to match( %r:/#{UUID_PATTERN}$: )
|
173
164
|
|
174
165
|
uuid = res.headers.x_thingfish_uuid
|
175
|
-
expect(
|
166
|
+
expect( handler.metastore.fetch_value(uuid, 'title') ).
|
176
167
|
to eq( 'Muffin the Panda Goes To School' )
|
177
|
-
expect(
|
168
|
+
expect( handler.metastore.fetch_value(uuid, 'tags') ).to eq( 'rapper,ukraine,potap' )
|
178
169
|
end
|
179
170
|
|
180
171
|
|
181
172
|
it 'replaces content via PUT' do
|
182
|
-
uuid =
|
183
|
-
|
173
|
+
uuid = handler.datastore.save( text_io )
|
174
|
+
handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
184
175
|
|
185
|
-
req = factory.put( "/#{uuid}",
|
186
|
-
req.headers.content_length =
|
187
|
-
res =
|
176
|
+
req = factory.put( "/#{uuid}", png_io, content_type: 'image/png' )
|
177
|
+
req.headers.content_length = png_io.read.bytesize
|
178
|
+
res = handler.handle( req )
|
188
179
|
|
189
180
|
expect( res.status ).to eq( HTTP::NO_CONTENT )
|
190
|
-
expect(
|
191
|
-
expect(
|
181
|
+
expect( handler.datastore.fetch(uuid).read ).to eq( TEST_PNG_DATA )
|
182
|
+
expect( handler.metastore.fetch(uuid) ).to include( 'format' => 'image/png' )
|
192
183
|
end
|
193
184
|
|
194
185
|
|
195
186
|
it "doesn't care about the case of the UUID when replacing content via PUT" do
|
196
|
-
uuid =
|
197
|
-
|
187
|
+
uuid = handler.datastore.save( text_io )
|
188
|
+
handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
198
189
|
|
199
|
-
req = factory.put( "/#{uuid.upcase}",
|
200
|
-
req.headers.content_length =
|
201
|
-
res =
|
190
|
+
req = factory.put( "/#{uuid.upcase}", png_io, content_type: 'image/png' )
|
191
|
+
req.headers.content_length = png_io.read.bytesize
|
192
|
+
res = handler.handle( req )
|
202
193
|
|
203
194
|
expect( res.status ).to eq( HTTP::NO_CONTENT )
|
204
|
-
expect(
|
205
|
-
expect(
|
195
|
+
expect( handler.datastore.fetch(uuid).read ).to eq( TEST_PNG_DATA )
|
196
|
+
expect( handler.metastore.fetch(uuid) ).to include( 'format' => 'image/png' )
|
206
197
|
end
|
207
198
|
|
208
199
|
|
209
200
|
it 'can fetch all uploaded data' do
|
210
|
-
text_uuid =
|
211
|
-
|
201
|
+
text_uuid = handler.datastore.save( text_io )
|
202
|
+
handler.metastore.save( text_uuid, {
|
212
203
|
'format' => 'text/plain',
|
213
|
-
'extent' =>
|
204
|
+
'extent' => text_io.string.bytesize
|
214
205
|
})
|
215
|
-
png_uuid =
|
216
|
-
|
206
|
+
png_uuid = handler.datastore.save( png_io )
|
207
|
+
handler.metastore.save( png_uuid, {
|
217
208
|
'format' => 'image/png',
|
218
|
-
'extent' =>
|
209
|
+
'extent' => png_io.string.bytesize
|
219
210
|
})
|
220
211
|
|
221
212
|
req = factory.get( '/' )
|
222
|
-
res =
|
213
|
+
res = handler.handle( req )
|
223
214
|
content = Yajl::Parser.parse( res.body.read )
|
224
215
|
|
225
216
|
expect( res.status_line ).to match( /200 ok/i )
|
@@ -228,30 +219,30 @@ describe Thingfish::Handler do
|
|
228
219
|
expect( content[0] ).to be_a( Hash )
|
229
220
|
expect( content[0]['uri'] ).to eq( "#{req.base_uri}#{text_uuid}" )
|
230
221
|
expect( content[0]['format'] ).to eq( "text/plain" )
|
231
|
-
expect( content[0]['extent'] ).to eq(
|
222
|
+
expect( content[0]['extent'] ).to eq( text_io.string.bytesize )
|
232
223
|
expect( content[1] ).to be_a( Hash )
|
233
224
|
expect( content[1]['uri'] ).to eq( "#{req.base_uri}#{png_uuid}" )
|
234
225
|
expect( content[1]['format'] ).to eq( 'image/png' )
|
235
|
-
expect( content[1]['extent'] ).to eq(
|
226
|
+
expect( content[1]['extent'] ).to eq( png_io.string.bytesize )
|
236
227
|
end
|
237
228
|
|
238
229
|
|
239
230
|
it 'can fetch all related data for a single resource' do
|
240
|
-
main_uuid =
|
241
|
-
|
231
|
+
main_uuid = handler.datastore.save( png_io )
|
232
|
+
handler.metastore.save( main_uuid, {
|
242
233
|
'format' => 'image/png',
|
243
|
-
'extent' =>
|
234
|
+
'extent' => png_io.string.bytesize
|
244
235
|
})
|
245
|
-
related_uuid =
|
246
|
-
|
236
|
+
related_uuid = handler.datastore.save( png_io )
|
237
|
+
handler.metastore.save( related_uuid, {
|
247
238
|
'format' => 'image/png',
|
248
|
-
'extent' =>
|
239
|
+
'extent' => png_io.string.bytesize,
|
249
240
|
'relation' => main_uuid,
|
250
241
|
'relationship' => "twinsies"
|
251
242
|
})
|
252
243
|
|
253
244
|
req = factory.get( "/#{main_uuid}/related" )
|
254
|
-
res =
|
245
|
+
res = handler.handle( req )
|
255
246
|
content = Yajl::Parser.parse( res.body.read )
|
256
247
|
|
257
248
|
expect( res.status_line ).to match( /200 ok/i )
|
@@ -260,146 +251,190 @@ describe Thingfish::Handler do
|
|
260
251
|
expect( content[0] ).to be_a( Hash )
|
261
252
|
expect( content[0]['uri'] ).to eq( "#{req.base_uri}#{related_uuid}" )
|
262
253
|
expect( content[0]['format'] ).to eq( "image/png" )
|
263
|
-
expect( content[0]['extent'] ).to eq(
|
254
|
+
expect( content[0]['extent'] ).to eq( png_io.string.bytesize )
|
264
255
|
expect( content[0]['uuid'] ).to eq( related_uuid )
|
265
256
|
expect( content[0]['relation'] ).to eq( main_uuid )
|
266
257
|
end
|
267
258
|
|
268
259
|
|
269
260
|
it 'can fetch a related resource by name' do
|
270
|
-
main_uuid =
|
271
|
-
|
261
|
+
main_uuid = handler.datastore.save( png_io )
|
262
|
+
handler.metastore.save( main_uuid, {
|
272
263
|
'format' => 'image/png',
|
273
|
-
'extent' =>
|
264
|
+
'extent' => png_io.string.bytesize
|
274
265
|
})
|
275
|
-
related_uuid =
|
276
|
-
|
266
|
+
related_uuid = handler.datastore.save( png_io )
|
267
|
+
handler.metastore.save( related_uuid, {
|
277
268
|
'format' => 'image/png',
|
278
|
-
'extent' =>
|
269
|
+
'extent' => png_io.string.bytesize,
|
279
270
|
'relation' => main_uuid,
|
280
|
-
'relationship' => "twinsies"
|
271
|
+
'relationship' => "twinsies",
|
272
|
+
'title' => 'Make America Smart Again.png',
|
273
|
+
'checksum' => '123456'
|
281
274
|
})
|
282
275
|
|
283
276
|
req = factory.get( "/#{main_uuid}/related/twinsies" )
|
284
|
-
res =
|
277
|
+
res = handler.handle( req )
|
285
278
|
|
286
279
|
expect( res.status_line ).to match( /200 ok/i )
|
287
280
|
expect( res.headers.content_type ).to eq( 'image/png' )
|
281
|
+
expect( res.headers.etag ).to eq( '123456' )
|
282
|
+
expect( res.headers.content_disposition ).to eq( 'filename="Make America Smart Again.png"' )
|
288
283
|
expect( res.body.read ).to eq( TEST_PNG_DATA )
|
289
284
|
end
|
290
285
|
|
291
286
|
|
292
287
|
it "404s when attempting to fetch a resource related to a non-existant resource" do
|
293
288
|
req = factory.get( "/#{TEST_UUID}/related/twinsies" )
|
294
|
-
res =
|
289
|
+
res = handler.handle( req )
|
295
290
|
|
296
291
|
expect( res.status_line ).to match( /404 not found/i )
|
297
292
|
end
|
298
293
|
|
299
294
|
|
300
295
|
it "404s when attempting to fetch a related resource that doesn't exist" do
|
301
|
-
uuid =
|
302
|
-
|
296
|
+
uuid = handler.datastore.save( png_io )
|
297
|
+
handler.metastore.save( uuid, {
|
303
298
|
'format' => 'image/png',
|
304
|
-
'extent' =>
|
299
|
+
'extent' => png_io.string.bytesize
|
305
300
|
})
|
306
301
|
|
307
302
|
req = factory.get( "/#{uuid}/related/twinsies" )
|
308
|
-
res =
|
303
|
+
res = handler.handle( req )
|
309
304
|
|
310
305
|
expect( res.status_line ).to match( /404 not found/i )
|
311
306
|
end
|
312
307
|
|
313
308
|
|
314
309
|
it "can fetch an uploaded chunk of data" do
|
315
|
-
uuid =
|
316
|
-
|
310
|
+
uuid = handler.datastore.save( png_io )
|
311
|
+
handler.metastore.save( uuid, {'format' => 'image/png'} )
|
317
312
|
|
318
313
|
req = factory.get( "/#{uuid}" )
|
319
|
-
result =
|
314
|
+
result = handler.handle( req )
|
320
315
|
|
321
316
|
expect( result.status_line ).to match( /200 ok/i )
|
322
|
-
expect( result.body.read ).to eq(
|
317
|
+
expect( result.body.read ).to eq( png_io.string )
|
323
318
|
expect( result.headers.content_type ).to eq( 'image/png' )
|
324
319
|
end
|
325
320
|
|
326
321
|
|
327
322
|
it "returns a 404 Not Found when asked to fetch an object that doesn't exist" do
|
328
323
|
req = factory.get( "/#{TEST_UUID}" )
|
329
|
-
result =
|
324
|
+
result = handler.handle( req )
|
330
325
|
|
331
326
|
expect( result.status_line ).to match( /404 not found/i )
|
332
327
|
end
|
333
328
|
|
334
329
|
|
335
330
|
it "returns a 404 Not Found when asked to fetch an object that doesn't exist in the metastore" do
|
336
|
-
uuid =
|
331
|
+
uuid = handler.datastore.save( png_io )
|
337
332
|
|
338
333
|
req = factory.get( "/#{uuid}" )
|
339
|
-
result =
|
334
|
+
result = handler.handle( req )
|
340
335
|
|
341
336
|
expect( result.status_line ).to match( /404 not found/i )
|
342
337
|
end
|
343
338
|
|
344
339
|
|
345
340
|
it "doesn't care about the case of the UUID when fetching uploaded data" do
|
346
|
-
uuid =
|
347
|
-
|
341
|
+
uuid = handler.datastore.save( png_io )
|
342
|
+
handler.metastore.save( uuid, {'format' => 'image/png'} )
|
348
343
|
|
349
344
|
req = factory.get( "/#{uuid.upcase}" )
|
350
|
-
result =
|
345
|
+
result = handler.handle( req )
|
351
346
|
|
352
347
|
expect( result.status_line ).to match( /200 ok/i )
|
353
|
-
expect( result.body.read ).to eq(
|
348
|
+
expect( result.body.read ).to eq( png_io.string )
|
354
349
|
expect( result.headers.content_type ).to eq( 'image/png' )
|
355
350
|
end
|
356
351
|
|
357
352
|
|
358
|
-
it "adds
|
359
|
-
|
360
|
-
|
353
|
+
it "adds date cache headers to resources" do
|
354
|
+
created = Time.now
|
355
|
+
uuid = handler.datastore.save( png_io )
|
356
|
+
handler.metastore.save( uuid, 'format' => 'image/png', 'created' => created )
|
361
357
|
|
362
358
|
req = factory.get( "/#{uuid}" )
|
363
|
-
result =
|
359
|
+
result = handler.handle( req )
|
360
|
+
|
361
|
+
expect( result.status_line ).to match( /200 ok/i )
|
362
|
+
expect( result.headers.last_modified ).to eq( created.httpdate )
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
it "adds content cache headers to resources with a checksum attribute" do
|
367
|
+
uuid = handler.datastore.save( png_io )
|
368
|
+
handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
|
369
|
+
|
370
|
+
req = factory.get( "/#{uuid}" )
|
371
|
+
result = handler.handle( req )
|
364
372
|
|
365
373
|
expect( result.status_line ).to match( /200 ok/i )
|
366
374
|
expect( result.headers.etag ).to eq( '123456' )
|
367
375
|
end
|
368
376
|
|
369
377
|
|
370
|
-
it "
|
371
|
-
uuid =
|
372
|
-
|
378
|
+
it "adds content disposition filename, if the resource has a title" do
|
379
|
+
uuid = handler.datastore.save( png_io )
|
380
|
+
handler.metastore.save( uuid, {'format' => 'image/png', 'title' => 'spょler"py.txt'} )
|
373
381
|
|
374
382
|
req = factory.get( "/#{uuid}" )
|
375
|
-
|
376
|
-
|
383
|
+
result = handler.handle( req )
|
384
|
+
|
385
|
+
expect( result.status_line ).to match( /200 ok/i )
|
386
|
+
expect( result.body.read ).to eq( png_io.string )
|
387
|
+
expect( result.headers.content_type ).to eq( 'image/png' )
|
388
|
+
expect( result.headers.content_disposition ).to eq( 'filename="sp?ler\"py.txt"' )
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
it "returns a 304 not modified for unchanged date cache requests" do
|
393
|
+
created = Time.now
|
394
|
+
uuid = handler.datastore.save( png_io )
|
395
|
+
handler.metastore.save( uuid, 'format' => 'image/png', 'created' => created )
|
396
|
+
|
397
|
+
req = factory.get( "/#{uuid}" )
|
398
|
+
req.headers[ :if_modified_since ] = ( Time.now - 300 ).httpdate
|
399
|
+
result = handler.handle( req )
|
377
400
|
|
378
401
|
expect( result.status_line ).to match( /304 not modified/i )
|
379
402
|
expect( result.body.read ).to be_empty
|
380
403
|
end
|
381
404
|
|
382
405
|
|
406
|
+
it "returns a 304 not modified for unchanged content cache requests" do
|
407
|
+
uuid = handler.datastore.save( png_io )
|
408
|
+
handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' )
|
409
|
+
|
410
|
+
req = factory.get( "/#{uuid}" )
|
411
|
+
req.headers[ :if_none_match ] = '123456'
|
412
|
+
result = handler.handle( req )
|
413
|
+
|
414
|
+
expect( result.status_line ).to match( /304 not modified/i )
|
415
|
+
expect( result.body.read ).to be_empty
|
416
|
+
end
|
417
|
+
|
383
418
|
|
384
419
|
it "can remove everything associated with an object id" do
|
385
|
-
uuid =
|
386
|
-
|
420
|
+
uuid = handler.datastore.save( png_io )
|
421
|
+
handler.metastore.save( uuid, {
|
387
422
|
'format' => 'image/png',
|
388
423
|
'extent' => 288,
|
389
424
|
})
|
390
425
|
|
391
426
|
req = factory.delete( "/#{uuid}" )
|
392
|
-
result =
|
427
|
+
result = handler.handle( req )
|
393
428
|
|
394
429
|
expect( result.status_line ).to match( /200 ok/i )
|
395
|
-
expect(
|
396
|
-
expect(
|
430
|
+
expect( handler.metastore.include?(uuid) ).to be_falsey
|
431
|
+
expect( handler.datastore.include?(uuid) ).to be_falsey
|
397
432
|
end
|
398
433
|
|
399
434
|
|
400
435
|
it "returns a 404 Not Found when asked to remove an object that doesn't exist" do
|
401
436
|
req = factory.delete( "/#{TEST_UUID}" )
|
402
|
-
result =
|
437
|
+
result = handler.handle( req )
|
403
438
|
|
404
439
|
expect( result.status_line ).to match( /404 not found/i )
|
405
440
|
end
|
@@ -417,15 +452,15 @@ describe Thingfish::Handler do
|
|
417
452
|
end
|
418
453
|
|
419
454
|
it "can fetch the metadata associated with uploaded data" do
|
420
|
-
uuid =
|
421
|
-
|
455
|
+
uuid = handler.datastore.save( png_io )
|
456
|
+
handler.metastore.save( uuid, {
|
422
457
|
'format' => 'image/png',
|
423
458
|
'extent' => 288,
|
424
459
|
'created' => Time.at(1378313840),
|
425
460
|
})
|
426
461
|
|
427
462
|
req = factory.get( "/#{uuid}/metadata" )
|
428
|
-
result =
|
463
|
+
result = handler.handle( req )
|
429
464
|
content = result.body.read
|
430
465
|
|
431
466
|
content_hash = Yajl::Parser.parse( content )
|
@@ -433,7 +468,7 @@ describe Thingfish::Handler do
|
|
433
468
|
expect( result.status ).to eq( 200 )
|
434
469
|
expect( result.headers.content_type ).to eq( 'application/json' )
|
435
470
|
expect( content_hash ).to be_a( Hash )
|
436
|
-
expect( content_hash['
|
471
|
+
expect( content_hash['uuid'] ).to eq( uuid )
|
437
472
|
expect( content_hash['extent'] ).to eq( 288 )
|
438
473
|
expect( content_hash['created'] ).to eq( Time.at(1378313840).to_s )
|
439
474
|
end
|
@@ -441,21 +476,21 @@ describe Thingfish::Handler do
|
|
441
476
|
|
442
477
|
it "returns a 404 Not Found when fetching metadata for an object that doesn't exist" do
|
443
478
|
req = factory.get( "/#{TEST_UUID}/metadata" )
|
444
|
-
result =
|
479
|
+
result = handler.handle( req )
|
445
480
|
|
446
481
|
expect( result.status_line ).to match( /404 not found/i )
|
447
482
|
end
|
448
483
|
|
449
484
|
|
450
485
|
it "can fetch a value for a single metadata key" do
|
451
|
-
uuid =
|
452
|
-
|
486
|
+
uuid = handler.datastore.save( png_io )
|
487
|
+
handler.metastore.save( uuid, {
|
453
488
|
'format' => 'image/png',
|
454
489
|
'extent' => 288,
|
455
490
|
})
|
456
491
|
|
457
492
|
req = factory.get( "/#{uuid}/metadata/extent" )
|
458
|
-
result =
|
493
|
+
result = handler.handle( req )
|
459
494
|
result.body.rewind
|
460
495
|
content = result.body.read
|
461
496
|
|
@@ -467,21 +502,21 @@ describe Thingfish::Handler do
|
|
467
502
|
|
468
503
|
it "returns a 404 Not Found when fetching a single metadata value for a uuid that doesn't exist" do
|
469
504
|
req = factory.get( "/#{TEST_UUID}/metadata/extent" )
|
470
|
-
result =
|
505
|
+
result = handler.handle( req )
|
471
506
|
|
472
507
|
expect( result.status_line ).to match( /404 not found/i )
|
473
508
|
end
|
474
509
|
|
475
510
|
|
476
511
|
it "doesn't error when fetching a non-existent metadata value" do
|
477
|
-
uuid =
|
478
|
-
|
512
|
+
uuid = handler.datastore.save( png_io )
|
513
|
+
handler.metastore.save( uuid, {
|
479
514
|
'format' => 'image/png',
|
480
515
|
'extent' => 288,
|
481
516
|
})
|
482
517
|
|
483
518
|
req = factory.get( "/#{uuid}/metadata/hururrgghh" )
|
484
|
-
result =
|
519
|
+
result = handler.handle( req )
|
485
520
|
|
486
521
|
content = Yajl::Parser.parse( result.body.read )
|
487
522
|
|
@@ -493,59 +528,58 @@ describe Thingfish::Handler do
|
|
493
528
|
|
494
529
|
|
495
530
|
it "can merge in new metadata for an existing resource with a POST" do
|
496
|
-
uuid =
|
497
|
-
|
531
|
+
uuid = handler.datastore.save( png_io )
|
532
|
+
handler.metastore.save( uuid, {
|
498
533
|
'format' => 'image/png',
|
499
|
-
'extent' => 288
|
534
|
+
'extent' => 288
|
500
535
|
})
|
501
536
|
|
502
|
-
body_json = Yajl.dump({ 'comment' => 'Ignore me!' })
|
537
|
+
body_json = Yajl.dump({ 'comment' => 'Ignore me!', 'uuid' => 123 })
|
503
538
|
req = factory.post( "/#{uuid}/metadata", body_json, 'Content-type' => 'application/json' )
|
504
|
-
result =
|
539
|
+
result = handler.handle( req )
|
505
540
|
|
506
|
-
expect( result.status ).to eq( HTTP::
|
507
|
-
expect(
|
541
|
+
expect( result.status ).to eq( HTTP::OK )
|
542
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Ignore me!' )
|
543
|
+
expect( handler.metastore.fetch_value(uuid, 'uuid') ).to be_nil
|
508
544
|
end
|
509
545
|
|
510
546
|
|
511
|
-
it "
|
512
|
-
uuid =
|
513
|
-
|
547
|
+
it "ignores attempts to alter operational metadata when merging" do
|
548
|
+
uuid = handler.datastore.save( png_io )
|
549
|
+
handler.metastore.save( uuid, {
|
514
550
|
'format' => 'image/png',
|
515
551
|
'extent' => 288,
|
516
552
|
})
|
517
553
|
|
518
554
|
body_json = Yajl.dump({ 'format' => 'text/plain', 'comment' => 'Ignore me!' })
|
519
555
|
req = factory.post( "/#{uuid}/metadata", body_json, 'Content-type' => 'application/json' )
|
520
|
-
result =
|
556
|
+
result = handler.handle( req )
|
521
557
|
|
522
|
-
expect( result.status ).to eq( HTTP::
|
523
|
-
expect(
|
524
|
-
expect(
|
525
|
-
expect( @handler.metastore.fetch_value(uuid, 'comment') ).to be_nil
|
526
|
-
expect( @handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
558
|
+
expect( result.status ).to eq( HTTP::OK )
|
559
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Ignore me!' )
|
560
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
527
561
|
end
|
528
562
|
|
529
563
|
|
530
564
|
it "can create single metadata values with a POST" do
|
531
|
-
uuid =
|
532
|
-
|
565
|
+
uuid = handler.datastore.save( png_io )
|
566
|
+
handler.metastore.save( uuid, {
|
533
567
|
'format' => 'image/png',
|
534
568
|
'extent' => 288,
|
535
569
|
})
|
536
570
|
|
537
571
|
req = factory.post( "/#{uuid}/metadata/comment", "urrrg", 'Content-type' => 'text/plain' )
|
538
|
-
result =
|
572
|
+
result = handler.handle( req )
|
539
573
|
|
540
574
|
expect( result.status ).to eq( HTTP::CREATED )
|
541
575
|
expect( result.headers.location ).to match( %r|#{uuid}/metadata/comment$| )
|
542
|
-
expect(
|
576
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'urrrg' )
|
543
577
|
end
|
544
578
|
|
545
579
|
|
546
580
|
it "returns NOT_FOUND when attempting to create metadata for a non-existent object" do
|
547
581
|
req = factory.post( "/#{TEST_UUID}/metadata/comment", "urrrg", 'Content-type' => 'text/plain' )
|
548
|
-
result =
|
582
|
+
result = handler.handle( req )
|
549
583
|
|
550
584
|
expect( result.status ).to eq( HTTP::NOT_FOUND )
|
551
585
|
expect( result.body.string ).to match( /no such object/i )
|
@@ -553,73 +587,73 @@ describe Thingfish::Handler do
|
|
553
587
|
|
554
588
|
|
555
589
|
it "returns CONFLICT when attempting to create a single metadata value if it already exists" do
|
556
|
-
uuid =
|
557
|
-
|
590
|
+
uuid = handler.datastore.save( png_io )
|
591
|
+
handler.metastore.save( uuid, {
|
558
592
|
'format' => 'image/png',
|
559
593
|
'extent' => 288,
|
560
594
|
'comment' => 'nill bill'
|
561
595
|
})
|
562
596
|
|
563
597
|
req = factory.post( "/#{uuid}/metadata/comment", "urrrg", 'Content-type' => 'text/plain' )
|
564
|
-
result =
|
598
|
+
result = handler.handle( req )
|
565
599
|
|
566
600
|
expect( result.status ).to eq( HTTP::CONFLICT )
|
567
601
|
expect( result.body.string ).to match( /already exists/i )
|
568
|
-
expect(
|
602
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'nill bill' )
|
569
603
|
end
|
570
604
|
|
571
605
|
|
572
606
|
it "can create single metadata values with a PUT" do
|
573
|
-
uuid =
|
574
|
-
|
607
|
+
uuid = handler.datastore.save( png_io )
|
608
|
+
handler.metastore.save( uuid, {
|
575
609
|
'format' => 'image/png',
|
576
610
|
'extent' => 288,
|
577
611
|
})
|
578
612
|
|
579
613
|
req = factory.put( "/#{uuid}/metadata/comment", "urrrg", 'Content-type' => 'text/plain' )
|
580
|
-
result =
|
614
|
+
result = handler.handle( req )
|
581
615
|
|
582
616
|
expect( result.status ).to eq( HTTP::NO_CONTENT )
|
583
|
-
expect(
|
617
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'urrrg' )
|
584
618
|
end
|
585
619
|
|
586
620
|
|
587
621
|
it "can replace a single metadata value with a PUT" do
|
588
|
-
uuid =
|
589
|
-
|
622
|
+
uuid = handler.datastore.save( png_io )
|
623
|
+
handler.metastore.save( uuid, {
|
590
624
|
'format' => 'image/png',
|
591
625
|
'extent' => 288,
|
592
626
|
'comment' => 'nill bill'
|
593
627
|
})
|
594
628
|
|
595
629
|
req = factory.put( "/#{uuid}/metadata/comment", "urrrg", 'Content-type' => 'text/plain' )
|
596
|
-
result =
|
630
|
+
result = handler.handle( req )
|
597
631
|
|
598
632
|
expect( result.status ).to eq( HTTP::NO_CONTENT )
|
599
|
-
expect(
|
633
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'urrrg' )
|
600
634
|
end
|
601
635
|
|
602
636
|
|
603
637
|
it "returns FORBIDDEN when attempting to replace a operational metadata value with a PUT" do
|
604
|
-
uuid =
|
605
|
-
|
638
|
+
uuid = handler.datastore.save( png_io )
|
639
|
+
handler.metastore.save( uuid, {
|
606
640
|
'format' => 'image/png',
|
607
641
|
'extent' => 288,
|
608
642
|
'comment' => 'nill bill'
|
609
643
|
})
|
610
644
|
|
611
645
|
req = factory.put( "/#{uuid}/metadata/format", "image/gif", 'Content-type' => 'text/plain' )
|
612
|
-
result =
|
646
|
+
result = handler.handle( req )
|
613
647
|
|
614
648
|
expect( result.status ).to eq( HTTP::FORBIDDEN )
|
615
649
|
expect( result.body.string ).to match( /protected metadata/i )
|
616
|
-
expect(
|
650
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
617
651
|
end
|
618
652
|
|
619
653
|
|
620
654
|
it "can replace all metadata with a PUT" do
|
621
|
-
uuid =
|
622
|
-
|
655
|
+
uuid = handler.datastore.save( png_io )
|
656
|
+
handler.metastore.save( uuid, {
|
623
657
|
'format' => 'image/png',
|
624
658
|
'extent' => 288,
|
625
659
|
'comment' => 'nill bill',
|
@@ -628,19 +662,19 @@ describe Thingfish::Handler do
|
|
628
662
|
|
629
663
|
req = factory.put( "/#{uuid}/metadata", %[{"comment":"Yeah."}],
|
630
664
|
'Content-type' => 'application/json' )
|
631
|
-
result =
|
665
|
+
result = handler.handle( req )
|
632
666
|
|
633
|
-
expect( result.status ).to eq( HTTP::
|
634
|
-
expect(
|
635
|
-
expect(
|
636
|
-
expect(
|
667
|
+
expect( result.status ).to eq( HTTP::OK )
|
668
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to eq( 'Yeah.' )
|
669
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
670
|
+
expect( handler.metastore ).to_not include( 'ephemeral' )
|
637
671
|
end
|
638
672
|
|
639
673
|
|
640
674
|
it "can remove all non-default metadata with a DELETE" do
|
641
675
|
timestamp = Time.now.getgm
|
642
|
-
uuid =
|
643
|
-
|
676
|
+
uuid = handler.datastore.save( png_io )
|
677
|
+
handler.metastore.save( uuid, {
|
644
678
|
'format' => 'image/png',
|
645
679
|
'extent' => 288,
|
646
680
|
'comment' => 'nill bill',
|
@@ -650,49 +684,49 @@ describe Thingfish::Handler do
|
|
650
684
|
})
|
651
685
|
|
652
686
|
req = factory.delete( "/#{uuid}/metadata" )
|
653
|
-
result =
|
687
|
+
result = handler.handle( req )
|
654
688
|
|
655
|
-
expect( result.status ).to eq( HTTP::
|
656
|
-
expect( result.body.string ).
|
657
|
-
expect(
|
658
|
-
expect(
|
659
|
-
expect(
|
660
|
-
expect(
|
689
|
+
expect( result.status ).to eq( HTTP::OK )
|
690
|
+
expect( result.body.string ).to_not be_empty
|
691
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
692
|
+
expect( handler.metastore.fetch_value(uuid, 'extent') ).to eq( 288 )
|
693
|
+
expect( handler.metastore.fetch_value(uuid, 'uploadaddress') ).to eq( '127.0.0.1' )
|
694
|
+
expect( handler.metastore.fetch_value(uuid, 'created') ).to eq( timestamp )
|
661
695
|
|
662
|
-
expect(
|
663
|
-
expect(
|
696
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to be_nil
|
697
|
+
expect( handler.metastore.fetch_value(uuid, 'useragent') ).to be_nil
|
664
698
|
end
|
665
699
|
|
666
700
|
|
667
701
|
it "can remove a single metadata value with DELETE" do
|
668
|
-
uuid =
|
669
|
-
|
702
|
+
uuid = handler.datastore.save( png_io )
|
703
|
+
handler.metastore.save( uuid, {
|
670
704
|
'format' => 'image/png',
|
671
705
|
'comment' => 'nill bill'
|
672
706
|
})
|
673
707
|
|
674
708
|
req = factory.delete( "/#{uuid}/metadata/comment" )
|
675
|
-
result =
|
709
|
+
result = handler.handle( req )
|
676
710
|
|
677
711
|
expect( result.status ).to eq( HTTP::NO_CONTENT )
|
678
712
|
expect( result.body.string ).to be_empty
|
679
|
-
expect(
|
680
|
-
expect(
|
713
|
+
expect( handler.metastore.fetch_value(uuid, 'comment') ).to be_nil
|
714
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
681
715
|
end
|
682
716
|
|
683
717
|
|
684
718
|
it "returns FORBIDDEN when attempting to remove a operational metadata value with a DELETE" do
|
685
|
-
uuid =
|
686
|
-
|
719
|
+
uuid = handler.datastore.save( png_io )
|
720
|
+
handler.metastore.save( uuid, {
|
687
721
|
'format' => 'image/png'
|
688
722
|
})
|
689
723
|
|
690
724
|
req = factory.delete( "/#{uuid}/metadata/format" )
|
691
|
-
result =
|
725
|
+
result = handler.handle( req )
|
692
726
|
|
693
727
|
expect( result.status ).to eq( HTTP::FORBIDDEN )
|
694
728
|
expect( result.body.string ).to match( /protected metadata/i )
|
695
|
-
expect(
|
729
|
+
expect( handler.metastore.fetch_value(uuid, 'format') ).to eq( 'image/png' )
|
696
730
|
end
|
697
731
|
end
|
698
732
|
|
@@ -777,23 +811,23 @@ describe Thingfish::Handler do
|
|
777
811
|
|
778
812
|
req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
|
779
813
|
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
780
|
-
res =
|
814
|
+
res = handler.handle( req )
|
781
815
|
uuid = res.headers.x_thingfish_uuid
|
782
816
|
|
783
|
-
Thingfish.logger.debug "Metastore contains: %p" % [
|
817
|
+
Thingfish.logger.debug "Metastore contains: %p" % [ handler.metastore.storage ]
|
784
818
|
|
785
|
-
expect(
|
819
|
+
expect( handler.metastore.fetch(uuid) ).
|
786
820
|
to include( 'test:comment' => 'Yo, it totally worked.')
|
787
|
-
related_uuids =
|
821
|
+
related_uuids = handler.metastore.fetch_related_oids( uuid )
|
788
822
|
expect( related_uuids.size ).to eq( 1 )
|
789
823
|
|
790
824
|
r_uuid = related_uuids.first.downcase
|
791
|
-
expect(
|
792
|
-
expect(
|
793
|
-
expect(
|
794
|
-
expect(
|
825
|
+
expect( handler.metastore.fetch_value(r_uuid, 'relation') ).to eq( uuid )
|
826
|
+
expect( handler.metastore.fetch_value(r_uuid, 'format') ).to eq( 'text/plain' )
|
827
|
+
expect( handler.metastore.fetch_value(r_uuid, 'extent') ).to eq( 9 )
|
828
|
+
expect( handler.metastore.fetch_value(r_uuid, 'relationship') ).to eq( 'comment' )
|
795
829
|
|
796
|
-
expect(
|
830
|
+
expect( handler.datastore.fetch(r_uuid).read ).to eq( 'Chunkers!' )
|
797
831
|
end
|
798
832
|
|
799
833
|
|
@@ -802,7 +836,7 @@ describe Thingfish::Handler do
|
|
802
836
|
processor = described_class.processors.first
|
803
837
|
|
804
838
|
req = factory.post( "/#{TEST_UUID}/metadata", TEST_TEXT_DATA, content_type: 'text/plain' )
|
805
|
-
|
839
|
+
handler.handle( req )
|
806
840
|
|
807
841
|
expect( processor.was_called ).to be_falsey
|
808
842
|
end
|
@@ -811,11 +845,11 @@ describe Thingfish::Handler do
|
|
811
845
|
it "processes responses" do
|
812
846
|
described_class.configure( :processors => %w[test] )
|
813
847
|
|
814
|
-
uuid =
|
815
|
-
|
848
|
+
uuid = handler.datastore.save( text_io )
|
849
|
+
handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
816
850
|
|
817
851
|
req = factory.get( "/#{uuid}" )
|
818
|
-
res =
|
852
|
+
res = handler.handle( req )
|
819
853
|
|
820
854
|
res.body.rewind
|
821
855
|
expect( res.body.read ).to eq( TEST_TEXT_DATA.reverse )
|
@@ -826,11 +860,11 @@ describe Thingfish::Handler do
|
|
826
860
|
described_class.configure( :processors => %w[test] )
|
827
861
|
processor = described_class.processors.first
|
828
862
|
|
829
|
-
uuid =
|
830
|
-
|
863
|
+
uuid = handler.datastore.save( text_io )
|
864
|
+
handler.metastore.save( uuid, {'format' => 'text/plain'} )
|
831
865
|
|
832
866
|
req = factory.get( "/#{uuid}/metadata" )
|
833
|
-
|
867
|
+
handler.handle( req )
|
834
868
|
|
835
869
|
expect( processor.was_called ).to be_falsey
|
836
870
|
end
|
@@ -846,12 +880,12 @@ describe Thingfish::Handler do
|
|
846
880
|
end
|
847
881
|
|
848
882
|
before( :each ) do
|
849
|
-
|
883
|
+
handler.setup_event_socket
|
850
884
|
|
851
|
-
@subsock =
|
852
|
-
@subsock.linger = 0
|
885
|
+
@subsock = CZTop::Socket::SUB.new
|
886
|
+
@subsock.options.linger = 0
|
853
887
|
@subsock.subscribe( '' )
|
854
|
-
@subsock.connect(
|
888
|
+
@subsock.connect( handler.event_socket.last_endpoint )
|
855
889
|
end
|
856
890
|
|
857
891
|
after( :each ) do
|
@@ -861,20 +895,20 @@ describe Thingfish::Handler do
|
|
861
895
|
it "publishes notifications about uploaded assets to a PUBSUB socket" do
|
862
896
|
req = factory.post( '/', TEST_TEXT_DATA, content_type: 'text/plain' )
|
863
897
|
req.headers.content_length = TEST_TEXT_DATA.bytesize
|
864
|
-
res = @handler.handle( req )
|
865
898
|
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
899
|
+
poller = CZTop::Poller.new
|
900
|
+
poller.add_reader( @subsock )
|
901
|
+
|
902
|
+
handler.handle( req )
|
903
|
+
event = poller.wait( 500 )
|
904
|
+
|
905
|
+
expect( event ).to_not be_nil
|
870
906
|
|
871
|
-
|
872
|
-
expect(
|
873
|
-
expect( event ).to eq( 'created' )
|
907
|
+
message = event.socket.receive
|
908
|
+
expect( message.frames.count ).to be( 2 )
|
874
909
|
|
875
|
-
|
876
|
-
expect(
|
877
|
-
expect( resource ).to match( /^\{"uuid":"#{UUID_PATTERN}"\}$/ )
|
910
|
+
expect( message.frames.first.to_s ).to eq( 'created' )
|
911
|
+
expect( message.frames.last.to_s ).to match( /^\{"uuid":"#{UUID_PATTERN}"\}$/ )
|
878
912
|
end
|
879
913
|
end
|
880
914
|
|