blobsterix 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +27 -0
  2. data/CHANGELOG.txt +13 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +22 -0
  5. data/README.md +122 -0
  6. data/Rakefile +13 -0
  7. data/bin/blobsterix +152 -0
  8. data/bin/test +26 -0
  9. data/blobsterix.gemspec +39 -0
  10. data/config/lighttpd.conf +50 -0
  11. data/lib/blobsterix.rb +213 -0
  12. data/lib/blobsterix/blob/blob_api.rb +55 -0
  13. data/lib/blobsterix/blob/blob_url_helper.rb +55 -0
  14. data/lib/blobsterix/helper/accept_type.rb +62 -0
  15. data/lib/blobsterix/helper/blob_access.rb +73 -0
  16. data/lib/blobsterix/helper/config_loader.rb +33 -0
  17. data/lib/blobsterix/helper/data_response.rb +54 -0
  18. data/lib/blobsterix/helper/http.rb +47 -0
  19. data/lib/blobsterix/helper/logable.rb +11 -0
  20. data/lib/blobsterix/helper/murmur.rb +137 -0
  21. data/lib/blobsterix/helper/status_info.rb +42 -0
  22. data/lib/blobsterix/helper/template_renderer.rb +39 -0
  23. data/lib/blobsterix/mimemagic/magic.rb +138 -0
  24. data/lib/blobsterix/mimemagic/tables.rb +1770 -0
  25. data/lib/blobsterix/mimemagic/version.rb +5 -0
  26. data/lib/blobsterix/router/app_router.rb +134 -0
  27. data/lib/blobsterix/s3/s3_api.rb +92 -0
  28. data/lib/blobsterix/s3/s3_url_helper.rb +93 -0
  29. data/lib/blobsterix/service.rb +34 -0
  30. data/lib/blobsterix/status/status_api.rb +62 -0
  31. data/lib/blobsterix/status/status_url_helper.rb +11 -0
  32. data/lib/blobsterix/storage/blob_meta_data.rb +60 -0
  33. data/lib/blobsterix/storage/bucket.rb +36 -0
  34. data/lib/blobsterix/storage/bucket_entry.rb +29 -0
  35. data/lib/blobsterix/storage/bucket_list.rb +26 -0
  36. data/lib/blobsterix/storage/cache.rb +90 -0
  37. data/lib/blobsterix/storage/file_system.rb +132 -0
  38. data/lib/blobsterix/storage/file_system_meta_data.rb +136 -0
  39. data/lib/blobsterix/storage/storage.rb +30 -0
  40. data/lib/blobsterix/transformation/image_transformation.rb +439 -0
  41. data/lib/blobsterix/transformation/transformation.rb +30 -0
  42. data/lib/blobsterix/transformation/transformation_chain.rb +78 -0
  43. data/lib/blobsterix/transformation/transformation_manager.rb +115 -0
  44. data/lib/blobsterix/version.rb +3 -0
  45. data/scripts/download.rb +30 -0
  46. data/scripts/test +6 -0
  47. data/spec/lib/blob/blob_api_spec.rb +81 -0
  48. data/spec/lib/helper/blob_access_spec.rb +72 -0
  49. data/spec/lib/s3/s3_api_spec.rb +183 -0
  50. data/spec/lib/service_spec.rb +12 -0
  51. data/spec/lib/status/status_api_spec.rb +42 -0
  52. data/spec/lib/storage/cache_spec.rb +135 -0
  53. data/spec/lib/storage/file_system_spec.rb +84 -0
  54. data/spec/spec_helper.rb +139 -0
  55. data/templates/app/Gemfile +12 -0
  56. data/templates/app/Rakefile +7 -0
  57. data/templates/app/config.rb +61 -0
  58. data/templates/app/config/environments/development.rb +40 -0
  59. data/templates/app/config/environments/production.rb +40 -0
  60. data/templates/app/storages/.keep +0 -0
  61. data/templates/app/transformators/.keep +0 -0
  62. data/templates/app/views/.keep +0 -0
  63. data/templates/storage_template.rb +30 -0
  64. data/templates/transformation_template.rb +41 -0
  65. data/templates/views/error_page.erb +18 -0
  66. data/templates/views/status_page.erb +31 -0
  67. 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
@@ -0,0 +1,3 @@
1
+ module Blobsterix
2
+ VERSION = "0.0.9"
3
+ end
@@ -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