blobsterix 0.0.9
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.
- data/.gitignore +27 -0
- data/CHANGELOG.txt +13 -0
- data/Gemfile +16 -0
- data/LICENSE +22 -0
- data/README.md +122 -0
- data/Rakefile +13 -0
- data/bin/blobsterix +152 -0
- data/bin/test +26 -0
- data/blobsterix.gemspec +39 -0
- data/config/lighttpd.conf +50 -0
- data/lib/blobsterix.rb +213 -0
- data/lib/blobsterix/blob/blob_api.rb +55 -0
- data/lib/blobsterix/blob/blob_url_helper.rb +55 -0
- data/lib/blobsterix/helper/accept_type.rb +62 -0
- data/lib/blobsterix/helper/blob_access.rb +73 -0
- data/lib/blobsterix/helper/config_loader.rb +33 -0
- data/lib/blobsterix/helper/data_response.rb +54 -0
- data/lib/blobsterix/helper/http.rb +47 -0
- data/lib/blobsterix/helper/logable.rb +11 -0
- data/lib/blobsterix/helper/murmur.rb +137 -0
- data/lib/blobsterix/helper/status_info.rb +42 -0
- data/lib/blobsterix/helper/template_renderer.rb +39 -0
- data/lib/blobsterix/mimemagic/magic.rb +138 -0
- data/lib/blobsterix/mimemagic/tables.rb +1770 -0
- data/lib/blobsterix/mimemagic/version.rb +5 -0
- data/lib/blobsterix/router/app_router.rb +134 -0
- data/lib/blobsterix/s3/s3_api.rb +92 -0
- data/lib/blobsterix/s3/s3_url_helper.rb +93 -0
- data/lib/blobsterix/service.rb +34 -0
- data/lib/blobsterix/status/status_api.rb +62 -0
- data/lib/blobsterix/status/status_url_helper.rb +11 -0
- data/lib/blobsterix/storage/blob_meta_data.rb +60 -0
- data/lib/blobsterix/storage/bucket.rb +36 -0
- data/lib/blobsterix/storage/bucket_entry.rb +29 -0
- data/lib/blobsterix/storage/bucket_list.rb +26 -0
- data/lib/blobsterix/storage/cache.rb +90 -0
- data/lib/blobsterix/storage/file_system.rb +132 -0
- data/lib/blobsterix/storage/file_system_meta_data.rb +136 -0
- data/lib/blobsterix/storage/storage.rb +30 -0
- data/lib/blobsterix/transformation/image_transformation.rb +439 -0
- data/lib/blobsterix/transformation/transformation.rb +30 -0
- data/lib/blobsterix/transformation/transformation_chain.rb +78 -0
- data/lib/blobsterix/transformation/transformation_manager.rb +115 -0
- data/lib/blobsterix/version.rb +3 -0
- data/scripts/download.rb +30 -0
- data/scripts/test +6 -0
- data/spec/lib/blob/blob_api_spec.rb +81 -0
- data/spec/lib/helper/blob_access_spec.rb +72 -0
- data/spec/lib/s3/s3_api_spec.rb +183 -0
- data/spec/lib/service_spec.rb +12 -0
- data/spec/lib/status/status_api_spec.rb +42 -0
- data/spec/lib/storage/cache_spec.rb +135 -0
- data/spec/lib/storage/file_system_spec.rb +84 -0
- data/spec/spec_helper.rb +139 -0
- data/templates/app/Gemfile +12 -0
- data/templates/app/Rakefile +7 -0
- data/templates/app/config.rb +61 -0
- data/templates/app/config/environments/development.rb +40 -0
- data/templates/app/config/environments/production.rb +40 -0
- data/templates/app/storages/.keep +0 -0
- data/templates/app/transformators/.keep +0 -0
- data/templates/app/views/.keep +0 -0
- data/templates/storage_template.rb +30 -0
- data/templates/transformation_template.rb +41 -0
- data/templates/views/error_page.erb +18 -0
- data/templates/views/status_page.erb +31 -0
- metadata +325 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
module Blobsterix::Transformations
|
2
|
+
class Transformation
|
3
|
+
include Blobsterix::Logable
|
4
|
+
|
5
|
+
def name
|
6
|
+
""
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
name
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_format?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def input_type
|
18
|
+
Blobsterix::AcceptType.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def output_type
|
22
|
+
Blobsterix::AcceptType.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def transform(input_path, target_path, value)
|
26
|
+
logger.debug "run transformation!!!!!"
|
27
|
+
system("cp #{input_path} #{target_path}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Blobsterix::Transformations
|
2
|
+
class TransformationChain
|
3
|
+
attr_reader :logger, :target_blob_access
|
4
|
+
|
5
|
+
def initialize(blob_access, input_data, logger)
|
6
|
+
@blob_access=blob_access
|
7
|
+
@target_blob_access=nil
|
8
|
+
@input_data = input_data
|
9
|
+
@transformations = []
|
10
|
+
@logger = logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def cache
|
14
|
+
@cache||=Blobsterix.cache
|
15
|
+
end
|
16
|
+
|
17
|
+
def last_type()
|
18
|
+
return Blobsterix::AcceptType.new(@input_data.mimetype) if @transformations.empty?
|
19
|
+
@transformations.last[0].output_type
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(transfo, value)
|
23
|
+
return if transfo == nil
|
24
|
+
@transformations << [transfo, value]
|
25
|
+
end
|
26
|
+
|
27
|
+
def do()
|
28
|
+
|
29
|
+
with_tempfiles do |keys|
|
30
|
+
last_key = "#{@input_data.path}"
|
31
|
+
|
32
|
+
begin
|
33
|
+
current_transformation = nil
|
34
|
+
@transformations.each{|trafo|
|
35
|
+
|
36
|
+
current_transformation = trafo
|
37
|
+
|
38
|
+
new_key = keys.delete_at(0)
|
39
|
+
trafo[0].transform(last_key, new_key, trafo[1])
|
40
|
+
last_key = new_key
|
41
|
+
}
|
42
|
+
rescue StandardError => e
|
43
|
+
logger.error "Transformation: #{current_transformation} failed with #{e.message}"
|
44
|
+
break
|
45
|
+
end
|
46
|
+
|
47
|
+
cache.put(@target_blob_access,Blobsterix::Storage::FileSystemMetaData.new(last_key).read)
|
48
|
+
@target_blob_access.reset!
|
49
|
+
end unless @target_blob_access.get.valid
|
50
|
+
|
51
|
+
@target_blob_access
|
52
|
+
end
|
53
|
+
|
54
|
+
def finish(accept_type, trafo)
|
55
|
+
if @transformations.empty? or (not @transformations.last[0].output_type.equal?(accept_type) and not @transformations.last[0].is_format?)
|
56
|
+
@transformations << [trafo, nil] if trafo != nil && trafo.is_format?
|
57
|
+
end
|
58
|
+
accept_type = @transformations.empty? || !@transformations.last[0].is_format? ? nil : @transformations.last[0].output_type
|
59
|
+
@target_blob_access = Blobsterix::BlobAccess.new(:bucket => @blob_access.bucket, :id => @blob_access.id, :trafo => @transformations.map{|trafo,value| [trafo.name, value]}, :accept_type => accept_type)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def with_tempfiles
|
65
|
+
tmpFiles = @transformations.size.times.map{|index|
|
66
|
+
Tempfile.new("#{@blob_access.identifier}_#{index}")
|
67
|
+
}
|
68
|
+
keys = tmpFiles.map{|f| f.path }
|
69
|
+
|
70
|
+
yield keys
|
71
|
+
|
72
|
+
tmpFiles.each { |f|
|
73
|
+
f.close
|
74
|
+
f.unlink
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Blobsterix::Transformations
|
2
|
+
#a TransormationManager cares about:
|
3
|
+
class TransformationManager
|
4
|
+
include Blobsterix::Logable
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
auto_load
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(trafo)
|
11
|
+
transformation = (trafo.is_a?(String) ? ::Blobsterix::Transformations::Impl::const_get(trafo).new : trafo)
|
12
|
+
transformations << transformation if transformations.select{|trafo|trafo.name === transformation.name}.empty?
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(blob_access)
|
17
|
+
|
18
|
+
blob_access = wait_for_transformation(blob_access) if transformation_in_progress?(blob_access)
|
19
|
+
|
20
|
+
return blob_access.get if blob_access.get.valid
|
21
|
+
|
22
|
+
cue_transformation(blob_access)
|
23
|
+
|
24
|
+
blob_access = run_transformation(blob_access)
|
25
|
+
|
26
|
+
blob_access.get.valid ? blob_access.get : Blobsterix::Storage::BlobMetaData.new
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def running_transformations
|
31
|
+
@running_transformations ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def transformations
|
35
|
+
@transformations ||= []
|
36
|
+
end
|
37
|
+
|
38
|
+
def wait_for_transformation(blob_access)
|
39
|
+
running_transformations[blob_access.identifier] << Fiber.current
|
40
|
+
logger.debug "Transformation: wait for it to finish #{blob_access}"
|
41
|
+
Fiber.yield
|
42
|
+
end
|
43
|
+
|
44
|
+
def cue_transformation(blob_access)
|
45
|
+
running_transformations[blob_access.identifier] = [Fiber.current]
|
46
|
+
blob_access
|
47
|
+
end
|
48
|
+
|
49
|
+
def uncue_transformation(blob_access)
|
50
|
+
running_transformations.delete(blob_access.identifier)
|
51
|
+
blob_access
|
52
|
+
end
|
53
|
+
|
54
|
+
def transformation_in_progress?(blob_access)
|
55
|
+
running = running_transformations.has_key?(blob_access.identifier)
|
56
|
+
running
|
57
|
+
end
|
58
|
+
|
59
|
+
def auto_load()
|
60
|
+
Blobsterix::Transformations::Impl.constants.each{|c|
|
61
|
+
add(c.to_s)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def run_transformation(blob_access)
|
66
|
+
logger.debug "Transformation: build #{blob_access}"
|
67
|
+
|
68
|
+
metaData = blob_access.source || Blobsterix::BlobAccess.new(:bucket => blob_access.bucket,:id => blob_access.id).get
|
69
|
+
|
70
|
+
return uncue_transformation(blob_access) unless metaData.valid
|
71
|
+
|
72
|
+
chain = TransformationChain.new(blob_access, metaData, logger)
|
73
|
+
|
74
|
+
blob_access.trafo.each {|trafo_pair|
|
75
|
+
chain.add(findTransformation(trafo_pair[0], chain.last_type), trafo_pair[1])
|
76
|
+
}
|
77
|
+
|
78
|
+
chain.finish(blob_access.accept_type, findTransformation_out(chain.last_type, blob_access.accept_type))
|
79
|
+
|
80
|
+
if chain.target_blob_access.get.valid
|
81
|
+
uncue_transformation(blob_access)
|
82
|
+
chain.target_blob_access
|
83
|
+
else
|
84
|
+
logger.debug "Transformation: run #{blob_access}"
|
85
|
+
EM.defer(Proc.new {
|
86
|
+
chain.do()
|
87
|
+
}, Proc.new {|result|
|
88
|
+
finish_connection(result, blob_access)
|
89
|
+
})
|
90
|
+
|
91
|
+
Fiber.yield
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def finish_connection(result, blob_access)
|
96
|
+
logger.debug "Transformation: done #{blob_access} finish connections"
|
97
|
+
running_transformations[blob_access.identifier].each{|fiber|
|
98
|
+
fiber.resume(result)
|
99
|
+
}
|
100
|
+
uncue_transformation(blob_access)
|
101
|
+
end
|
102
|
+
|
103
|
+
def findTransformation(name, input_type)
|
104
|
+
trafos = transformations.select{|trafo| trafo.name === name and trafo.input_type.is?(input_type)}
|
105
|
+
trafos.empty? ? nil : trafos[0]
|
106
|
+
end
|
107
|
+
|
108
|
+
def findTransformation_out(input_type, output_type)
|
109
|
+
trafos = transformations.select{|trafo|
|
110
|
+
trafo.input_type.is?(input_type) and trafo.output_type.equal?(output_type)
|
111
|
+
}
|
112
|
+
trafos.empty? ? nil : trafos[0]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/scripts/download.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
uri = URI.parse("http://localhost:9000/blob/v1/rotate_25,ascii_250.images/expired.pngd")
|
6
|
+
|
7
|
+
# Net::HTTP.start("localhost", 9000) do |http|
|
8
|
+
# resp = http.get("/images/syncview21force.png")
|
9
|
+
# open("/home/dsudmann/desktop/syncview21force.png", "wb") do |file|
|
10
|
+
# file.write(resp.body)
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
|
14
|
+
# Net::HTTP.start(uri.host,uri.port) do |http|
|
15
|
+
# resp = http.get(uri.path)
|
16
|
+
# open("/home/dsudmann/desktop/syncview21force.png", "wb") do |file|
|
17
|
+
# file.write(resp.body)
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
Net::HTTP.start(uri.host,uri.port) do |http|
|
22
|
+
open("/home/dsudmann/desktop/syncview21force", "wb") do |file|
|
23
|
+
http.request_get(uri.path){ |resp|
|
24
|
+
puts resp.code
|
25
|
+
resp.read_body{ |seg|
|
26
|
+
file << seg
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
data/scripts/test
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_10.images/expired.png > cache/log_00 &
|
2
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_20.images/expired.png > cache/log_01 &
|
3
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_30.images/expired.png > cache/log_02 &
|
4
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_40.images/expired.png > cache/log_03 &
|
5
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_50.images/expired.png > cache/log_04 &
|
6
|
+
ab -n 100 -c 50 http://localhost:3000/blob/v1/rotate_60.images/expired.png > cache/log_05 &
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Blobsterix::BlobApi do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
def app
|
6
|
+
Blobsterix::BlobApi
|
7
|
+
end
|
8
|
+
describe 'GET /blob/v1/' do
|
9
|
+
it 'get several categories of repositories by name' do
|
10
|
+
get "/blob/v1/"
|
11
|
+
expect(last_response.status).to eql(403)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'Transformed get' do
|
16
|
+
include Blobsterix::SpecHelper
|
17
|
+
|
18
|
+
context "with data" do
|
19
|
+
let(:data) {"Hi my name is Test"}
|
20
|
+
let(:data_transformed) {"Hi_my_name_is_Test_Transformed"}
|
21
|
+
let(:key) {"test.txt"}
|
22
|
+
let(:bucket) {"test"}
|
23
|
+
|
24
|
+
before :all do
|
25
|
+
Blobsterix.transformation.add Blobsterix::SpecHelper::DummyTrafo.new
|
26
|
+
end
|
27
|
+
|
28
|
+
after :all do
|
29
|
+
Blobsterix.transformation=Blobsterix::Transformations::TransformationManager.new
|
30
|
+
end
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
34
|
+
end
|
35
|
+
|
36
|
+
after :each do
|
37
|
+
clear_data
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return the file" do
|
41
|
+
expect(Blobsterix.transformation).to receive(:cue_transformation).once.and_call_original
|
42
|
+
run_em do
|
43
|
+
get "/blob/v1/dummy_#{data_transformed}.test/test.txt"
|
44
|
+
end
|
45
|
+
expect(last_response.status).to eql(200)
|
46
|
+
expect(last_response.body).to eql(data_transformed)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return the file head" do
|
50
|
+
expect(Blobsterix.transformation).to receive(:cue_transformation).once.and_call_original
|
51
|
+
run_em do
|
52
|
+
head "/blob/v1/dummy.test/test.txt"
|
53
|
+
end
|
54
|
+
expect(last_response.status).to eql(200)
|
55
|
+
expect(last_response.body).to eql("")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return the file and wait for previous trafos to finish" do
|
59
|
+
expect(Blobsterix.transformation).to receive(:cue_transformation).once.and_call_original
|
60
|
+
expect(Blobsterix.transformation).to receive(:wait_for_transformation).once.and_call_original
|
61
|
+
run_em do
|
62
|
+
get "/blob/v1/dummy_#{data_transformed}.test/test.txt"
|
63
|
+
get "/blob/v1/dummy_#{data_transformed}.test/test.txt"
|
64
|
+
end
|
65
|
+
expect(last_response.status).to eql(200)
|
66
|
+
expect(last_response.body).to eql(data_transformed)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should return the file and not wait for different trafos to finish" do
|
70
|
+
expect(Blobsterix.transformation).to receive(:cue_transformation).twice.and_call_original
|
71
|
+
expect(Blobsterix.transformation).to receive(:wait_for_transformation).never.and_call_original
|
72
|
+
run_em do
|
73
|
+
get "/blob/v1/dummy_#{data_transformed},dummy_#{data_transformed}.test/test.txt"
|
74
|
+
get "/blob/v1/dummy_#{data_transformed}.test/test.txt"
|
75
|
+
end
|
76
|
+
expect(last_response.status).to eql(200)
|
77
|
+
expect(last_response.body).to eql(data_transformed)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Blobsterix::BlobAccess do
|
4
|
+
include Blobsterix::SpecHelper
|
5
|
+
|
6
|
+
let(:data) {"Hi my name is Test"}
|
7
|
+
let(:key) {"test.txt"}
|
8
|
+
let(:bucket) {"test"}
|
9
|
+
|
10
|
+
def blob_access
|
11
|
+
Blobsterix::BlobAccess.new(:bucket => bucket, :id => key)
|
12
|
+
end
|
13
|
+
def blob_access_1
|
14
|
+
Blobsterix::BlobAccess.new(:bucket => bucket, :id => key, :trafo => [["test", ""]])
|
15
|
+
end
|
16
|
+
def blob_access_raw
|
17
|
+
Blobsterix::BlobAccess.new(:bucket => bucket, :id => key, :trafo => [["raw", ""]])
|
18
|
+
end
|
19
|
+
def blob_access_same_accept_type
|
20
|
+
Blobsterix::BlobAccess.new(:bucket => bucket, :id => key, :accept_type => Blobsterix::AcceptType.new("text/plain"))
|
21
|
+
end
|
22
|
+
def blob_access_raw_same_accept_type
|
23
|
+
Blobsterix::BlobAccess.new(:bucket => bucket, :id => key, :trafo => [["raw", ""]], :accept_type => Blobsterix::AcceptType.new("text/plain"))
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "blob_access" do
|
27
|
+
after :each do
|
28
|
+
clear_data
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return valid blob data when it exists" do
|
32
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
33
|
+
expect(blob_access.get().valid).to be(true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return invalid blob data when it does not exist" do
|
37
|
+
expect(blob_access.get().valid).to be(false)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should automaticly guess raw trafo" do
|
41
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
42
|
+
expect(blob_access.get().valid).to be(true)
|
43
|
+
expect(blob_access_raw.get().valid).to be(true)
|
44
|
+
expect(blob_access_same_accept_type.get().valid).to be(true)
|
45
|
+
expect(blob_access_raw_same_accept_type.get().valid).to be(true)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "dont cache raw" do
|
49
|
+
before :each do
|
50
|
+
Blobsterix.cache_original= false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not create a cache entry for raw transforms" do
|
54
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
55
|
+
expect(blob_access.get().valid).to be(true)
|
56
|
+
expect(Blobsterix.cache.get(blob_access).valid).to be(false)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "cache raw" do
|
61
|
+
before :each do
|
62
|
+
Blobsterix.cache_original= true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should create a cache entry for raw transforms" do
|
66
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
67
|
+
expect(blob_access.get().valid).to be(true)
|
68
|
+
expect(Blobsterix.cache.get(blob_access).valid).to be(true)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Blobsterix::S3Api do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
include Blobsterix::SpecHelper
|
6
|
+
def app
|
7
|
+
Blobsterix::S3Api
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:data) {"Hi my name is Test"}
|
11
|
+
let(:key) {"test.txt"}
|
12
|
+
let(:bucket) {"test"}
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
clear_data
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "create a bucket" do
|
19
|
+
it "should have bucket after creation" do
|
20
|
+
|
21
|
+
run_em do
|
22
|
+
put "/", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
23
|
+
end
|
24
|
+
|
25
|
+
get "/#{bucket}"
|
26
|
+
expect(last_response.status).to eql(200)
|
27
|
+
response = Hash.from_xml last_response.body
|
28
|
+
expect(response).to_not have_key(:Error)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "upload" do
|
33
|
+
|
34
|
+
before :all do
|
35
|
+
Blobsterix.transformation.add Blobsterix::SpecHelper::DummyTrafo.new
|
36
|
+
end
|
37
|
+
|
38
|
+
after :all do
|
39
|
+
Blobsterix.transformation=Blobsterix::Transformations::TransformationManager.new
|
40
|
+
end
|
41
|
+
|
42
|
+
after :each do
|
43
|
+
clear_data
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have file in bucket after upload" do
|
47
|
+
#expect(Blobsterix.transformation).to receive(:cue_transformation).never.and_call_original
|
48
|
+
|
49
|
+
run_em do
|
50
|
+
put "/#{key}", data, {"HTTP_HOST" => "#{bucket}.s3.blah.de"}
|
51
|
+
end
|
52
|
+
|
53
|
+
expect(last_response.status).to eql(200)
|
54
|
+
expect(Blobsterix.storage.get(bucket, key).read).to eql(data)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have file in bucket after upload with trafo" do
|
58
|
+
#expect(Blobsterix.transformation).to receive(:cue_transformation).once.and_call_original
|
59
|
+
|
60
|
+
run_em do
|
61
|
+
put "/#{key}", data, {"HTTP_HOST" => "#{bucket}.s3.blah.de", "HTTP_X_AMZ_META_TRAFO" => "dummy_Yeah"}
|
62
|
+
end
|
63
|
+
|
64
|
+
expect(last_response.status).to eql(200)
|
65
|
+
expect(Blobsterix.storage.get(bucket, key).read).to eql("Yeah")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with no data" do
|
70
|
+
|
71
|
+
describe "bucket" do
|
72
|
+
it 'should return an empty set' do
|
73
|
+
get "/"
|
74
|
+
expect(last_response.status).to eql(200)
|
75
|
+
response = Hash.from_xml last_response.body
|
76
|
+
expect(response).to have_key(:ListAllMyBucketsResult)
|
77
|
+
expect(response[:ListAllMyBucketsResult]).to have_key(:Buckets)
|
78
|
+
expect(response[:ListAllMyBucketsResult][:Buckets]).to be_empty
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should say no such bucket' do
|
82
|
+
get "/#{bucket}"
|
83
|
+
expect(last_response.status).to eql(200)
|
84
|
+
response = Hash.from_xml last_response.body
|
85
|
+
expect(response).to have_key(:Error)
|
86
|
+
expect(response[:Error]).to eql("no such bucket")
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return 404 on delete bucket" do
|
90
|
+
expect(Blobsterix.storage.bucket_exist(bucket)).to eql(false)
|
91
|
+
|
92
|
+
delete "/", "", "HTTP_HOST" => "s3.blah.de"
|
93
|
+
|
94
|
+
expect(last_response.status).to eql(404)
|
95
|
+
expect(Blobsterix.storage.bucket_exist(bucket)).to eql(false)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'file' do
|
100
|
+
it "should return a 404 when bucket doesn't exist" do
|
101
|
+
get "/#{key}", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
102
|
+
expect(last_response.status).to eql(404)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should return a 404 when bucket exists' do
|
106
|
+
Blobsterix.storage.create(bucket)
|
107
|
+
get "/#{key}", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
108
|
+
expect(last_response.status).to eql(404)
|
109
|
+
Blobsterix.storage.delete(bucket)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with data" do
|
115
|
+
|
116
|
+
before :each do
|
117
|
+
Blobsterix.storage.put(bucket, key, StringIO.new(data, "r"))
|
118
|
+
end
|
119
|
+
|
120
|
+
after :each do
|
121
|
+
clear_storage
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "bucket" do
|
125
|
+
|
126
|
+
it 'should return one bucket in the list' do
|
127
|
+
get "/"
|
128
|
+
expect(last_response.status).to eql(200)
|
129
|
+
response = Hash.from_xml last_response.body
|
130
|
+
expect(response).to have_key(:ListAllMyBucketsResult)
|
131
|
+
expect(response[:ListAllMyBucketsResult]).to have_key(:Buckets)
|
132
|
+
expect(response[:ListAllMyBucketsResult][:Buckets]).to_not be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should return all files for the bucket' do
|
136
|
+
get "/#{bucket}"
|
137
|
+
expect(last_response.status).to eql(200)
|
138
|
+
response = Hash.from_xml last_response.body
|
139
|
+
expect(response).to have_key(:ListBucketResult)
|
140
|
+
expect(response[:ListBucketResult]).to have_key(:Name)
|
141
|
+
expect(response[:ListBucketResult][:Name]).to eql(bucket)
|
142
|
+
expect(response[:ListBucketResult][:Contents]).to_not be_empty
|
143
|
+
expect(response[:ListBucketResult][:Contents][:Key]).to eql(key)
|
144
|
+
expect(response[:ListBucketResult][:Contents][:MimeType]).to eql("text/plain")
|
145
|
+
expect(response[:ListBucketResult][:Contents][:Size]).to eql(data.length)
|
146
|
+
expect(response[:ListBucketResult][:Contents][:ETag]).to eql(Digest::MD5.hexdigest(data))
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should delete bucket" do
|
150
|
+
Blobsterix.storage.delete_key(bucket, key)
|
151
|
+
expect(Blobsterix.storage.bucket_exist(bucket)).to eql(true)
|
152
|
+
|
153
|
+
delete "/", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
154
|
+
|
155
|
+
expect(last_response.status).to eql(204)
|
156
|
+
expect(Blobsterix.storage.bucket_exist(bucket)).to eql(false)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "file" do
|
162
|
+
|
163
|
+
it "should return file" do
|
164
|
+
get "/#{key}", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
165
|
+
expect(last_response.status).to eql(200)
|
166
|
+
expect(last_response.body).to eql(data)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should return file head" do
|
170
|
+
head "/#{key}", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
171
|
+
expect(last_response.status).to eql(200)
|
172
|
+
expect(last_response.body).to eql("")
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should delete key" do
|
176
|
+
delete "/#{key}", "", "HTTP_HOST" => "#{bucket}.s3.blah.de"
|
177
|
+
|
178
|
+
expect(last_response.status).to eql(204)
|
179
|
+
expect(Blobsterix.storage.get(bucket, key).valid).to eql(false)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|