fragmenter 1.0.0.rc2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5931e8212db98c33d0d78dc0b857214a27f8c33
4
- data.tar.gz: 9cc17e75a60b88e87f75e561a7f203874e769898
3
+ metadata.gz: 492790d602b011f85a9c59b2e7730e897b50b4c2
4
+ data.tar.gz: 15ce8668a07766801e7d1fbfa946e0a51f8481f2
5
5
  SHA512:
6
- metadata.gz: 8f48a59ba0829ad7f7366a3e32c3ccb6c9639cabf6cae23fdf54bc6f877e5f184e20bc34e84f83c6cfc9a013923abf3c9deffc1eaf9502e0915fadfdc3bbd6c0
7
- data.tar.gz: 6b15e275846e7eb2d3199016f09f3a7e60a766850bdd17e3db49f0bfce624492b9721ea3c17b3dbb6bbd466ab78982fe98d6161cc05dafc4745b9ea525ee759c
6
+ metadata.gz: 5c5961781e29d00c847b1683e87f50daf5bff5998db3eb92c0acc61065c9a8a657c4a178b695f2002ae3fcc99a81db81e8047f5679403d058554ebb3d9e213f3
7
+ data.tar.gz: afe3e60454e3b2e304cd351562befcad35168fddc5d0624c4ca4c4284b174a0c318323bdecf09c6e631fb9d6f92b483ba77322bffd6e9099baea8073a3d8eb4e
@@ -1,3 +1,8 @@
1
+ # 1.0.0
2
+
3
+ * Provide a convenience IO wrapper for rebuilt data with `Wrapper#to_io`.
4
+ * Add integration specs for testing against the rack request/response interface
5
+
1
6
  # 1.0.0.rc2
2
7
 
3
8
  * Automatically rewind IO objects between reads. This fixes the issue of
data/README.md CHANGED
@@ -143,6 +143,18 @@ curl -i
143
143
  #=> { "content_type": "image/jpeg", "fragments": [1,2], "total": 2 }
144
144
  ```
145
145
 
146
+ If you need to customize the status codes for partial or complete `PUT`
147
+ requests you can override the `update_status` method within the controller:
148
+
149
+ ```ruby
150
+ private
151
+
152
+ # Return 201 Created instead of 202 Accepted
153
+ def update_status
154
+ uploader.complete? ? 201 : 200
155
+ end
156
+ ```
157
+
146
158
  ### Validation
147
159
 
148
160
  Often you will want to be sure that all of the data is being stored without any
data/fragmenter.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
10
10
  gem.email = ['parker@sorentwo.com']
11
11
  gem.homepage = 'https://github.com/dscout/fragmenter'
12
12
  gem.license = 'MIT'
13
- gem.description = %q{Fragmentize and rebuild data}
13
+ gem.description = 'Fragmentize and rebuild data'
14
14
  gem.summary = <<-SUMMARY
15
15
  Multipart upload support backed by Redis. Fragmenter handles storing
16
16
  multiple parts of a larger binary and rebuilding it back into the original
@@ -22,5 +22,7 @@ Gem::Specification.new do |gem|
22
22
  gem.require_paths = ['lib']
23
23
 
24
24
  gem.add_dependency 'redis', '~> 3.0.0'
25
- gem.add_development_dependency 'rspec', '~> 2.14.0'
25
+ gem.add_development_dependency 'rspec', '~> 2.14.0'
26
+ gem.add_development_dependency 'rack-test', '~> 0.6.2'
27
+ gem.add_development_dependency 'sinatra', '~> 1.4.3'
26
28
  end
data/lib/fragmenter.rb CHANGED
@@ -2,6 +2,7 @@ require 'logger'
2
2
  require 'redis'
3
3
  require 'fragmenter/redis'
4
4
  require 'fragmenter/version'
5
+ require 'fragmenter/dummy_io'
5
6
  require 'fragmenter/wrapper'
6
7
  require 'fragmenter/rails/controller'
7
8
  require 'fragmenter/rails/model'
@@ -0,0 +1,13 @@
1
+ module Fragmenter
2
+ class DummyIO < StringIO
3
+ attr_writer :content_type, :original_filename
4
+
5
+ def original_filename
6
+ @original_filename || ['dummy', content_type.split('/').last].join('.')
7
+ end
8
+
9
+ def content_type
10
+ @content_type || 'application/octet-stream'
11
+ end
12
+ end
13
+ end
@@ -2,7 +2,7 @@ module Fragmenter
2
2
  module Rails
3
3
  module Controller
4
4
  def show
5
- render json: fragmenter.as_json
5
+ render json: fragmenter.as_json, status: 200
6
6
  end
7
7
 
8
8
  def update
@@ -11,14 +11,14 @@ module Fragmenter
11
11
  else
12
12
  render json: {
13
13
  message: 'Upload of part failed.', errors: uploader.errors
14
- }, status: :unprocessable_entity
14
+ }, status: 422
15
15
  end
16
16
  end
17
17
 
18
18
  def destroy
19
19
  fragmenter.clean!
20
20
 
21
- render nothing: true, status: :no_content
21
+ render nothing: true, status: 204
22
22
  end
23
23
 
24
24
  private
@@ -37,13 +37,13 @@ module Fragmenter
37
37
  resource: resource,
38
38
  fragmenter: fragmenter,
39
39
  body: request.body,
40
- headers: request.headers
40
+ headers: request.env
41
41
  ), validators
42
42
  )
43
43
  end
44
44
 
45
45
  def update_status
46
- uploader.complete? ? :accepted : :ok
46
+ uploader.complete? ? 202 : 200
47
47
  end
48
48
  end
49
49
  end
@@ -1,3 +1,3 @@
1
1
  module Fragmenter
2
- VERSION = '1.0.0.rc2'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -23,5 +23,11 @@ module Fragmenter
23
23
  def as_json
24
24
  engine.meta.merge('fragments' => engine.fragments)
25
25
  end
26
+
27
+ def to_io
28
+ Fragmenter::DummyIO.new(rebuild).tap do |io|
29
+ io.content_type = meta['content_type']
30
+ end
31
+ end
26
32
  end
27
33
  end
@@ -0,0 +1,39 @@
1
+ require 'fragmenter/dummy_io'
2
+
3
+ describe Fragmenter::DummyIO do
4
+ it 'provies IO like access' do
5
+ io = Fragmenter::DummyIO.new
6
+
7
+ expect(io).to respond_to(:read)
8
+ expect(io).to respond_to(:length)
9
+ end
10
+
11
+ describe '#content_type' do
12
+ it 'defaults to application/octet-stream' do
13
+ expect(Fragmenter::DummyIO.new.content_type).to eq('application/octet-stream')
14
+ end
15
+
16
+ it 'can be overridden' do
17
+ io = Fragmenter::DummyIO.new
18
+ io.content_type = 'image/png'
19
+
20
+ expect(io.content_type).to eq('image/png')
21
+ end
22
+ end
23
+
24
+ describe '#original_filename' do
25
+ it 'defaults to a fake mime comprised of dummy and the content type' do
26
+ io = Fragmenter::DummyIO.new
27
+ io.content_type = 'image/png'
28
+
29
+ expect(io.original_filename).to eq('dummy.png')
30
+ end
31
+
32
+ it 'can be overriden' do
33
+ io = Fragmenter::DummyIO.new
34
+ io.original_filename = 'wonderful.png'
35
+
36
+ expect(io.original_filename).to eq('wonderful.png')
37
+ end
38
+ end
39
+ end
@@ -22,7 +22,8 @@ describe Fragmenter::Rails::Controller do
22
22
  controller.show
23
23
 
24
24
  expect(controller).to have_received(:render).with(
25
- json: { 'fragments' => [] }
25
+ json: { 'fragments' => [] },
26
+ status: 200
26
27
  )
27
28
  end
28
29
  end
@@ -40,7 +41,7 @@ describe Fragmenter::Rails::Controller do
40
41
  expect(resource.fragmenter).to have_received(:clean!)
41
42
  expect(controller).to have_received(:render).with(
42
43
  nothing: true,
43
- status: :no_content
44
+ status: 204
44
45
  )
45
46
  end
46
47
  end
@@ -59,7 +60,7 @@ describe Fragmenter::Rails::Controller do
59
60
  expect(uploader).to have_received(:store)
60
61
  expect(controller).to have_received(:render).with(
61
62
  json: { 'fragments' => [] },
62
- status: :ok
63
+ status: 200
63
64
  )
64
65
  end
65
66
 
@@ -78,7 +79,7 @@ describe Fragmenter::Rails::Controller do
78
79
  message: 'Upload of part failed.',
79
80
  errors: []
80
81
  },
81
- status: :unprocessable_entity
82
+ status: 422
82
83
  )
83
84
  end
84
85
  end
@@ -1,15 +1,17 @@
1
- require 'fragmenter/wrapper'
1
+ require 'fragmenter'
2
2
 
3
3
  describe Fragmenter::Wrapper do
4
4
  let(:object) { double(:object, id: 1001) }
5
5
  let(:engine_class) { double(:engine_class, new: engine) }
6
6
  let(:engine) { double(:engine) }
7
7
 
8
- subject(:base) { Fragmenter::Wrapper.new(object, engine_class) }
8
+ subject(:wrapper) do
9
+ Fragmenter::Wrapper.new(object, engine_class)
10
+ end
9
11
 
10
12
  describe '#key' do
11
13
  it 'composes a key from the object class and id value' do
12
- base.key.should match(/[a-z]+-\d+/)
14
+ expect(wrapper.key).to match(/[a-z]+-\d+/)
13
15
  end
14
16
  end
15
17
 
@@ -18,14 +20,14 @@ describe Fragmenter::Wrapper do
18
20
  let(:headers) { {} }
19
21
 
20
22
  it 'delegates #store to the storage engine' do
21
- engine.should_receive(:store).with(blob, headers)
23
+ expect(engine).to receive(:store).with(blob, headers)
22
24
 
23
- base.store(blob, headers)
25
+ wrapper.store(blob, headers)
24
26
  end
25
27
 
26
28
  it 'delegates #fragments to the storage engine' do
27
- engine.should_receive(:fragments)
28
- base.fragments
29
+ expect(engine).to receive(:fragments)
30
+ wrapper.fragments
29
31
  end
30
32
  end
31
33
 
@@ -34,9 +36,22 @@ describe Fragmenter::Wrapper do
34
36
  engine.stub('meta' => { 'content_type' => 'application/octet-stream' },
35
37
  'fragments' => ['1', '2'])
36
38
 
37
- base.as_json.tap do |json|
38
- json.should have_key('content_type')
39
- json.should have_key('fragments')
39
+ wrapper.as_json.tap do |json|
40
+ expect(json).to have_key('content_type')
41
+ expect(json).to have_key('fragments')
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '#to_io' do
47
+ it 'wraps the rebuilt data in a Rack::Multipart::UploadedFile compatible IO object' do
48
+ engine.stub(meta: { 'content_type' => 'image/png' }, rebuild: '0101010')
49
+
50
+ wrapper.to_io.tap do |io|
51
+ expect(io).to be_instance_of(Fragmenter::DummyIO)
52
+ expect(io.read).to eq('0101010')
53
+ expect(io.content_type).to eq('image/png')
54
+ expect(io.original_filename).to eq('dummy.png')
40
55
  end
41
56
  end
42
57
  end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+ require 'rack/test'
4
+ require 'support/resource'
5
+ require 'support/uploads_app'
6
+
7
+ describe 'Uploading Fragments' do
8
+ include Rack::Test::Methods
9
+
10
+ let(:app) { UploadsApp }
11
+ let(:resource) { Resource.new(200) }
12
+
13
+ around do |example|
14
+ UploadsApp.resource = resource
15
+ Fragmenter.logger = Logger.new('/dev/null')
16
+
17
+ example.run
18
+
19
+ Fragmenter.logger = nil
20
+ UploadsApp.resource = nil
21
+ end
22
+
23
+ it 'Lists uploaded fragments' do
24
+ get '/'
25
+
26
+ expect(last_response.status).to eq(200)
27
+ expect(decoded_response).to eq('fragments' => [])
28
+
29
+ store_fragment(number: 1, total: 2)
30
+
31
+ get '/'
32
+
33
+ expect(last_response.status).to eq(200)
34
+ expect(decoded_response).to eq(
35
+ 'content_type' => 'application/octet-stream',
36
+ 'fragments' => %w[1],
37
+ 'total' => '2'
38
+ )
39
+
40
+ clean_fragments!
41
+ end
42
+
43
+ it 'Stores uploaded fragments' do
44
+ header 'Content-Type', 'image/gif'
45
+ header 'X-Fragment-Number', '1'
46
+ header 'X-Fragment-Total', '2'
47
+
48
+ put '/', file_data('micro.gif')
49
+
50
+ expect(last_response.status).to eq(200)
51
+ expect(decoded_response).to eq(
52
+ 'content_type' => 'image/gif',
53
+ 'fragments' => %w[1],
54
+ 'total' => '2'
55
+ )
56
+
57
+ header 'X-Fragment-Number', '2'
58
+ header 'X-Fragment-Total', '2'
59
+
60
+ put '/', file_data('micro.gif')
61
+
62
+ expect(last_response.status).to eq(202)
63
+ expect(decoded_response).to eq('fragments' => [])
64
+ end
65
+
66
+ it 'Destroys uploaded fragments' do
67
+ store_fragment(number: 1, total: 2)
68
+
69
+ delete '/'
70
+
71
+ expect(last_response.status).to eq(204)
72
+ expect(last_response.body).to eq('')
73
+ expect(fragmenter.fragments.length).to be_zero
74
+ end
75
+
76
+ private
77
+
78
+ def file_data(file)
79
+ IO.read("spec/fixtures/#{file}")
80
+ end
81
+
82
+ def decoded_response
83
+ JSON.parse(last_response.body)
84
+ end
85
+
86
+ def fragmenter
87
+ resource.fragmenter
88
+ end
89
+
90
+ def store_fragment(options = {})
91
+ number = options[:number]
92
+ total = options[:total]
93
+
94
+ fragmenter.store(
95
+ '0101',
96
+ content_type: 'application/octet-stream',
97
+ number: number,
98
+ total: total
99
+ )
100
+ end
101
+
102
+ def clean_fragments!
103
+ resource.fragmenter.clean!
104
+ end
105
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,8 @@
1
+ require 'bundler'
1
2
  require 'fragmenter'
2
3
 
4
+ Bundler.setup
5
+
3
6
  RSpec.configure do |config|
4
7
  config.treat_symbols_as_metadata_keys_with_true_values = true
5
8
  config.run_all_when_everything_filtered = true
@@ -0,0 +1,9 @@
1
+ require 'fragmenter/rails/model'
2
+
3
+ Resource = Struct.new(:id) do
4
+ include Fragmenter::Rails::Model
5
+
6
+ def rebuild_fragments
7
+ fragmenter.rebuild && fragmenter.clean!
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'fragmenter/rails/controller'
2
+ require 'sinatra/base'
3
+
4
+ class UploadsApp < Sinatra::Base
5
+ include Fragmenter::Rails::Controller
6
+
7
+ class << self
8
+ attr_accessor :resource
9
+ end
10
+
11
+ get('/') { show }
12
+ put('/') { update }
13
+ delete('/') { destroy }
14
+
15
+ private
16
+
17
+ def resource
18
+ self.class.resource
19
+ end
20
+
21
+ def render(options)
22
+ body = if options[:json]
23
+ JSON.dump(options[:json])
24
+ else
25
+ nil
26
+ end
27
+
28
+ [options[:status], body]
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ require 'fragmenter'
2
+
3
+ class Uploads < Sinatra::Base
4
+ include Fragmenter::Rails::Controller
5
+
6
+ put '/' do
7
+ show
8
+ end
9
+ end
10
+
11
+ run Uploads
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fragmenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Parker Selbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-19 00:00:00.000000000 Z
11
+ date: 2013-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.14.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: sinatra
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.4.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.4.3
41
69
  description: Fragmentize and rebuild data
42
70
  email:
43
71
  - parker@sorentwo.com
@@ -48,13 +76,14 @@ files:
48
76
  - .gitignore
49
77
  - .rspec
50
78
  - .travis.yml
79
+ - CHANGELOG.md
51
80
  - Gemfile
52
- - HISTORY.md
53
81
  - LICENSE.txt
54
82
  - README.md
55
83
  - Rakefile
56
84
  - fragmenter.gemspec
57
85
  - lib/fragmenter.rb
86
+ - lib/fragmenter/dummy_io.rb
58
87
  - lib/fragmenter/fragment.rb
59
88
  - lib/fragmenter/rails/controller.rb
60
89
  - lib/fragmenter/rails/model.rb
@@ -67,6 +96,7 @@ files:
67
96
  - lib/fragmenter/version.rb
68
97
  - lib/fragmenter/wrapper.rb
69
98
  - spec/fixtures/micro.gif
99
+ - spec/fragmenter/dummy_io_spec.rb
70
100
  - spec/fragmenter/fragment_spec.rb
71
101
  - spec/fragmenter/rails/controller_spec.rb
72
102
  - spec/fragmenter/rails/model_spec.rb
@@ -78,7 +108,11 @@ files:
78
108
  - spec/fragmenter/validators/image_validator_spec.rb
79
109
  - spec/fragmenter/wrapper_spec.rb
80
110
  - spec/fragmenter_spec.rb
111
+ - spec/requests/uploading_fragments_spec.rb
81
112
  - spec/spec_helper.rb
113
+ - spec/support/resource.rb
114
+ - spec/support/uploads_app.rb
115
+ - spec/upload_server.rb
82
116
  homepage: https://github.com/dscout/fragmenter
83
117
  licenses:
84
118
  - MIT
@@ -94,9 +128,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
128
  version: '0'
95
129
  required_rubygems_version: !ruby/object:Gem::Requirement
96
130
  requirements:
97
- - - '>'
131
+ - - '>='
98
132
  - !ruby/object:Gem::Version
99
- version: 1.3.1
133
+ version: '0'
100
134
  requirements: []
101
135
  rubyforge_project:
102
136
  rubygems_version: 2.0.0
@@ -107,6 +141,7 @@ summary: Multipart upload support backed by Redis. Fragmenter handles storing mu
107
141
  have been stored.
108
142
  test_files:
109
143
  - spec/fixtures/micro.gif
144
+ - spec/fragmenter/dummy_io_spec.rb
110
145
  - spec/fragmenter/fragment_spec.rb
111
146
  - spec/fragmenter/rails/controller_spec.rb
112
147
  - spec/fragmenter/rails/model_spec.rb
@@ -118,4 +153,8 @@ test_files:
118
153
  - spec/fragmenter/validators/image_validator_spec.rb
119
154
  - spec/fragmenter/wrapper_spec.rb
120
155
  - spec/fragmenter_spec.rb
156
+ - spec/requests/uploading_fragments_spec.rb
121
157
  - spec/spec_helper.rb
158
+ - spec/support/resource.rb
159
+ - spec/support/uploads_app.rb
160
+ - spec/upload_server.rb