thingfish 0.5.0.pre20161103181816 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|