blobsterix 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|