blobstore_client 0.5.0 → 1.5.0.pre.1113

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/Rakefile DELETED
@@ -1,49 +0,0 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
- $:.unshift(File.expand_path("../../rake", __FILE__))
4
-
5
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
-
7
- require "rubygems"
8
- require "bundler"
9
- Bundler.setup(:default, :test)
10
-
11
- require "rake"
12
- begin
13
- require "rspec/core/rake_task"
14
- rescue LoadError
15
- end
16
-
17
- require "bundler_task"
18
- require "ci_task"
19
-
20
- gem_helper = Bundler::GemHelper.new(Dir.pwd)
21
-
22
- desc "Build Blobstore Client gem into the pkg directory"
23
- task "build" do
24
- gem_helper.build_gem
25
- end
26
-
27
- desc "Build and install Blobstore Client into system gems"
28
- task "install" do
29
- gem_helper.install_gem
30
- end
31
-
32
- BundlerTask.new
33
-
34
- if defined?(RSpec)
35
- namespace :spec do
36
- desc "Run Unit Tests"
37
- rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
38
- t.pattern = "spec/unit/**/*_spec.rb"
39
- t.rspec_opts = %w(--format progress --colour)
40
- end
41
-
42
- CiTask.new do |task|
43
- task.rspec_task = rspec_task
44
- end
45
- end
46
-
47
- desc "Install dependencies and run tests"
48
- task :spec => %w(spec:unit)
49
- end
data/spec/assets/file DELETED
@@ -1 +0,0 @@
1
- foobar
data/spec/spec_helper.rb DELETED
@@ -1,8 +0,0 @@
1
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
2
-
3
- require "rubygems"
4
- require "bundler"
5
- Bundler.setup(:default, :test)
6
-
7
- require "rspec"
8
- require "blobstore_client"
@@ -1,72 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- describe Bosh::Blobstore::AtmosBlobstoreClient do
4
-
5
- before(:each) do
6
- @atmos = mock("atmos")
7
- Atmos::Store.stub!(:new).and_return(@atmos)
8
- atmos_opt = {:url => "http://localhost",
9
- :uid => "uid",
10
- :secret => "secret"}
11
-
12
- @http_client = mock("http-client")
13
- ssl_opt = mock("ssl-opt")
14
- ssl_opt.stub!(:verify_mode=)
15
- @http_client.stub!(:ssl_config).and_return(ssl_opt)
16
-
17
- HTTPClient.stub!(:new).and_return(@http_client)
18
- @client = Bosh::Blobstore::AtmosBlobstoreClient.new(atmos_opt)
19
- end
20
-
21
- it "should create an object" do
22
- data = "some content"
23
- object = mock("object")
24
-
25
- @atmos.should_receive(:create).with {|opt|
26
- opt[:data].read.should eql data
27
- opt[:length].should eql data.length
28
- }.and_return(object)
29
-
30
- object.should_receive(:aoid).and_return("test-key")
31
-
32
- object_id = @client.create(data)
33
- object_info = MultiJson.decode(Base64.decode64(URI::unescape(object_id)))
34
- object_info["oid"].should eql("test-key")
35
- object_info["sig"].should_not be_nil
36
- end
37
-
38
- it "should delete an object" do
39
- object = mock("object")
40
- @atmos.should_receive(:get).with(:id => "test-key").and_return(object)
41
- object.should_receive(:delete)
42
- id = URI::escape(Base64.encode64(MultiJson.encode({:oid => "test-key", :sig => "sig"})))
43
- @client.delete(id)
44
- end
45
-
46
- it "should fetch an object" do
47
- url = "http://localhost/rest/objects/test-key?uid=uid&expires=1893484800&signature=sig"
48
- response = mock("response")
49
- response.stub!(:status).and_return(200)
50
- @http_client.should_receive(:get).with(url).and_yield("some-content").and_return(response)
51
- id = URI::escape(Base64.encode64(MultiJson.encode({:oid => "test-key", :sig => "sig"})))
52
- @client.get(id).should eql("some-content")
53
- end
54
-
55
- it "should refuse to create object without the password" do
56
- lambda {
57
- no_pass_client = Bosh::Blobstore::AtmosBlobstoreClient.new(:url => "http://localhost", :uid => "uid")
58
- no_pass_client.create("foo")
59
- }.should raise_error(Bosh::Blobstore::BlobstoreError)
60
- end
61
-
62
- it "should be able to read without password" do
63
- no_pass_client = Bosh::Blobstore::AtmosBlobstoreClient.new(:url => "http://localhost", :uid => "uid")
64
-
65
- url = "http://localhost/rest/objects/test-key?uid=uid&expires=1893484800&signature=sig"
66
- response = mock("response")
67
- response.stub!(:status).and_return(200)
68
- @http_client.should_receive(:get).with(url).and_yield("some-content").and_return(response)
69
- id = URI::escape(Base64.encode64(MultiJson.encode({:oid => "test-key", :sig => "sig"})))
70
- no_pass_client.get(id).should eql("some-content")
71
- end
72
- end
@@ -1,44 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- describe Bosh::Blobstore::Client do
4
-
5
- it "should have a local provider" do
6
- Dir.mktmpdir do |tmp|
7
- bs = Bosh::Blobstore::Client.create('local', {:blobstore_path => tmp})
8
- bs.should be_instance_of Bosh::Blobstore::LocalClient
9
- end
10
- end
11
-
12
- it "should have an simple provider" do
13
- bs = Bosh::Blobstore::Client.create('simple', {})
14
- bs.should be_instance_of Bosh::Blobstore::SimpleBlobstoreClient
15
- end
16
-
17
- it "should have an atmos provider" do
18
- bs = Bosh::Blobstore::Client.create('atmos', {})
19
- bs.should be_instance_of Bosh::Blobstore::AtmosBlobstoreClient
20
- end
21
-
22
- it "should have an s3 provider" do
23
- options = {:access_key_id => "foo", :secret_access_key => "bar"}
24
- bs = Bosh::Blobstore::Client.create('s3', options)
25
- bs.should be_instance_of Bosh::Blobstore::S3BlobstoreClient
26
- end
27
-
28
- it "should pick S3 provider when S3 is used without credentials" do
29
- bs = Bosh::Blobstore::Client.create('s3', {:bucket_name => "foo"})
30
- bs.should be_instance_of Bosh::Blobstore::S3BlobstoreClient
31
- end
32
-
33
- it "should have an swift provider" do
34
- bs = Bosh::Blobstore::Client.create('swift', {})
35
- bs.should be_instance_of Bosh::Blobstore::SwiftBlobstoreClient
36
- end
37
-
38
- it "should raise an exception on an unknown client" do
39
- lambda {
40
- bs = Bosh::Blobstore::Client.create('foobar', {})
41
- }.should raise_error /^Invalid client provider/
42
- end
43
-
44
- end
@@ -1,78 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- describe Bosh::Blobstore::LocalClient do
4
-
5
- before(:each) do
6
- @tmp = Dir.mktmpdir
7
- @options = {"blobstore_path" => @tmp}
8
- end
9
-
10
- after(:each) do
11
- FileUtils.rm_rf(@tmp)
12
- end
13
-
14
- it "should require blobstore_path option" do
15
- lambda {
16
- client = Bosh::Blobstore::LocalClient.new({})
17
- }.should raise_error
18
- end
19
-
20
- it "should create blobstore_path direcory if it doesn't exist'" do
21
- dir = File.join(@tmp, "blobstore")
22
- client = Bosh::Blobstore::LocalClient.new({"blobstore_path" => dir})
23
- File.directory?(dir).should be_true
24
- end
25
-
26
- describe "operations" do
27
-
28
- describe "get" do
29
- it "should retrive the correct contents" do
30
- File.open(File.join(@tmp, 'foo'), 'w') do |fh|
31
- fh.puts("bar")
32
- end
33
-
34
- client = Bosh::Blobstore::LocalClient.new(@options)
35
- client.get("foo").should == "bar\n"
36
- end
37
- end
38
-
39
- describe "create" do
40
- it "should store a file" do
41
- test_file = File.join(File.dirname(__FILE__), "../assets/file")
42
- client = Bosh::Blobstore::LocalClient.new(@options)
43
- fh = File.open(test_file)
44
- id = client.create(fh)
45
- fh.close
46
- original = File.new(test_file).readlines
47
- stored = File.new(File.join(@tmp, id)).readlines
48
- stored.should == original
49
- end
50
-
51
- it "should store a string" do
52
- client = Bosh::Blobstore::LocalClient.new(@options)
53
- string = "foobar"
54
- id = client.create(string)
55
- stored = File.new(File.join(@tmp, id)).readlines
56
- stored.should == [string]
57
- end
58
- end
59
-
60
- describe "delete" do
61
- it "should delete an id" do
62
- client = Bosh::Blobstore::LocalClient.new(@options)
63
- string = "foobar"
64
- id = client.create(string)
65
- client.delete(id)
66
- File.exist?(File.join(@tmp, id)).should_not be_true
67
- end
68
-
69
- it "should raise NotFound error when trying to delete a missing id" do
70
- client = Bosh::Blobstore::LocalClient.new(@options)
71
- lambda {
72
- client.delete("missing")
73
- }.should raise_error Bosh::Blobstore::NotFound
74
- end
75
- end
76
-
77
- end
78
- end
@@ -1,282 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- describe Bosh::Blobstore::S3BlobstoreClient do
4
-
5
- before(:each) do
6
- @aws_mock_options = {
7
- :access_key_id => "KEY",
8
- :secret_access_key => "SECRET",
9
- :use_ssl => true,
10
- :port => 443
11
- }
12
- end
13
-
14
- def s3_blobstore(options)
15
- Bosh::Blobstore::S3BlobstoreClient.new(options)
16
- end
17
-
18
- describe "read only mode" do
19
- it "does not establish S3 connection on creation" do
20
- AWS::S3::Base.should_not_receive(:establish_connection!)
21
- @client = s3_blobstore("bucket_name" => "test")
22
- end
23
-
24
- it "should raise an error on deletion" do
25
- @client = s3_blobstore("bucket_name" => "test")
26
- lambda {
27
- @client.delete("id")
28
- }.should raise_error "unsupported action"
29
- end
30
-
31
- it "should raise an error on creation" do
32
- @client = s3_blobstore("bucket_name" => "test")
33
- lambda {
34
- @client.create("id")
35
- }.should raise_error "unsupported action"
36
- end
37
-
38
- it "should fetch objects" do
39
- simple = mock("simple", :to_ary => nil, :get_file => %w[foo id])
40
- Bosh::Blobstore::SimpleBlobstoreClient.should_receive(:new).and_return(simple)
41
- @client = s3_blobstore("bucket_name" => "test")
42
- @client.get_file("foo", "id")
43
- end
44
- end
45
-
46
- describe "options" do
47
-
48
- it "establishes S3 connection on creation" do
49
- AWS::S3::Base.should_receive(:establish_connection!).with(@aws_mock_options)
50
-
51
- @client = s3_blobstore("encryption_key" => "bla",
52
- "bucket_name" => "test",
53
- "access_key_id" => "KEY",
54
- "secret_access_key" => "SECRET")
55
-
56
- @client.encryption_key.should == "bla"
57
- @client.bucket_name.should == "test"
58
- end
59
-
60
- it "supports Symbol option keys too" do
61
- AWS::S3::Base.should_receive(:establish_connection!).with(@aws_mock_options)
62
-
63
- @client = s3_blobstore(:encryption_key => "bla",
64
- :bucket_name => "test",
65
- :access_key_id => "KEY",
66
- :secret_access_key => "SECRET")
67
-
68
- @client.encryption_key.should == "bla"
69
- @client.bucket_name.should == "test"
70
- end
71
- end
72
-
73
- describe "operations" do
74
-
75
- before :each do
76
- @client = s3_blobstore(:encryption_key => "bla",
77
- :bucket_name => "test",
78
- :access_key_id => "KEY",
79
- :secret_access_key => "SECRET")
80
- end
81
-
82
- describe "create" do
83
-
84
- it "should create an object" do
85
- encrypted_file = nil
86
- @client.should_receive(:generate_object_id).and_return("object_id")
87
- @client.should_receive(:encrypt_stream).with { |from_file, _|
88
- from_file.read.should eql("some content")
89
- true
90
- }.and_return {|_, to_file|
91
- encrypted_file = to_file
92
- nil
93
- }
94
-
95
- AWS::S3::S3Object.should_receive(:store).with { |key, data, bucket|
96
- key.should eql("object_id")
97
- data.path.should eql(encrypted_file.path)
98
- bucket.should eql("test")
99
- true
100
- }
101
- @client.create("some content").should eql("object_id")
102
- end
103
-
104
- it "should not encrypt when encryption key is missing" do
105
- client = s3_blobstore(:bucket_name => "test",
106
- :access_key_id => "KEY",
107
- :secret_access_key => "SECRET")
108
- client.should_receive(:generate_object_id).and_return("object_id")
109
- client.should_not_receive(:encrypt_stream)
110
-
111
- AWS::S3::S3Object.should_receive(:store)
112
- client.create("some content").should eql("object_id")
113
- end
114
-
115
- it "should raise an exception when there is an error creating an object" do
116
- encrypted_file = nil
117
- @client.should_receive(:generate_object_id).and_return("object_id")
118
- @client.should_receive(:encrypt_stream).with { |from_file, _|
119
- from_file.read.should eql("some content")
120
- true
121
- }.and_return {|_, to_file|
122
- encrypted_file = to_file
123
- nil
124
- }
125
-
126
- AWS::S3::S3Object.should_receive(:store).with { |key, data, bucket|
127
- key.should eql("object_id")
128
- data.path.should eql(encrypted_file.path)
129
- bucket.should eql("test")
130
- true
131
- }.and_raise(AWS::S3::S3Exception.new("Epic Fail"))
132
- lambda {
133
- @client.create("some content")
134
- }.should raise_error(Bosh::Blobstore::BlobstoreError, "Failed to create object, S3 response error: Epic Fail")
135
- end
136
-
137
- end
138
-
139
- describe "fetch" do
140
-
141
- it "should fetch an object" do
142
- mock_s3_object = mock("s3_object")
143
- mock_s3_object.stub!(:value).and_yield("ENCRYPTED")
144
- AWS::S3::S3Object.should_receive(:find).with("object_id", "test").and_return(mock_s3_object)
145
- @client.should_receive(:decrypt_stream).with { |from, _|
146
- encrypted = ""
147
- from.call(lambda {|segment| encrypted << segment})
148
- encrypted.should eql("ENCRYPTED")
149
- true
150
- }.and_return {|_, to|
151
- to.write("stuff")
152
- }
153
- @client.get("object_id").should == "stuff"
154
- end
155
-
156
- it "should not decrypt when encryption key is missing" do
157
- client = s3_blobstore(:bucket_name => "test",
158
- :access_key_id => "KEY",
159
- :secret_access_key => "SECRET")
160
-
161
- mock_s3_object = mock("s3_object")
162
- mock_s3_object.stub!(:value).and_yield("stuff")
163
- AWS::S3::S3Object.should_receive(:find).with("object_id", "test").and_return(mock_s3_object)
164
- client.should_not_receive(:decrypt_stream)
165
-
166
- client.get("object_id").should == "stuff"
167
- end
168
-
169
- it "should raise an exception when there is an error fetching an object" do
170
- AWS::S3::S3Object.should_receive(:find).with("object_id", "test").and_raise(AWS::S3::S3Exception.new("Epic Fail"))
171
- lambda {
172
- @client.get("object_id")
173
- }.should raise_error(Bosh::Blobstore::BlobstoreError, "Failed to find object 'object_id', S3 response error: Epic Fail")
174
- end
175
-
176
- it "should raise more specific NotFound exception when object is not found" do
177
- AWS::S3::S3Object.should_receive(:find).with("object_id", "test").and_raise(AWS::S3::NoSuchKey.new("NO KEY", "test"))
178
- lambda {
179
- @client.get("object_id")
180
- }.should raise_error(Bosh::Blobstore::BlobstoreError, "S3 object 'object_id' not found")
181
- end
182
-
183
- end
184
-
185
- describe "delete" do
186
-
187
- it "should delete an object" do
188
- AWS::S3::S3Object.should_receive(:delete).with("object_id", "test")
189
- @client.delete("object_id")
190
- end
191
-
192
- it "should raise an exception when there is an error deleting an object" do
193
- AWS::S3::S3Object.should_receive(:delete).with("object_id", "test").and_raise(AWS::S3::S3Exception.new("Epic Fail"))
194
- lambda {
195
- @client.delete("object_id")
196
- }.should raise_error(Bosh::Blobstore::BlobstoreError, "Failed to delete object 'object_id', S3 response error: Epic Fail")
197
- end
198
-
199
- end
200
-
201
- describe "encryption" do
202
-
203
- before :each do
204
- @from_path = File.join(Dir::tmpdir, "from-#{UUIDTools::UUID.random_create}")
205
- @to_path = File.join(Dir::tmpdir, "to-#{UUIDTools::UUID.random_create}")
206
- end
207
-
208
- after :each do
209
- FileUtils.rm_f(@from_path)
210
- FileUtils.rm_f(@to_path)
211
- end
212
-
213
- it "encrypt/decrypt works as long as key is the same" do
214
- File.open(@from_path, "w") { |f| f.write("clear text") }
215
- File.open(@from_path, "r") do |from|
216
- File.open(@to_path, "w") do |to|
217
- @client.send(:encrypt_stream, from, to)
218
- end
219
- end
220
-
221
- Base64.encode64(File.read(@to_path)).should eql("XCUKDXXzjh43DmNylgVpQQ==\n")
222
-
223
- File.open(@from_path, "w") { |f| f.write(File.read(@to_path)) }
224
- File.open(@from_path, "r") do |from|
225
- File.open(@to_path, "w") do |to|
226
- @client.send(:decrypt_stream, from, to)
227
- end
228
- end
229
-
230
- File.read(@to_path).should eql("clear text")
231
- end
232
-
233
- it "encrypt/decrypt doesn't have padding issues for very small inputs" do
234
- File.open(@from_path, "w") { |f| f.write("c") }
235
- File.open(@from_path, "r") do |from|
236
- File.open(@to_path, "w") do |to|
237
- @client.send(:encrypt_stream, from, to)
238
- end
239
- end
240
-
241
- Base64.encode64(File.read(@to_path)).should eql("S1ZnX5gPfm/rQbRCcShHSg==\n")
242
-
243
- File.open(@from_path, "w") { |f| f.write(File.read(@to_path)) }
244
- File.open(@from_path, "r") do |from|
245
- File.open(@to_path, "w") do |to|
246
- @client.send(:decrypt_stream, from, to)
247
- end
248
- end
249
-
250
- File.read(@to_path).should eql("c")
251
- end
252
-
253
- it "should raise an exception if incorrect encryption key is used" do
254
- File.open(@from_path, "w") { |f| f.write("clear text") }
255
- File.open(@from_path, "r") do |from|
256
- File.open(@to_path, "w") do |to|
257
- @client.send(:encrypt_stream, from, to)
258
- end
259
- end
260
-
261
- Base64.encode64(File.read(@to_path)).should eql("XCUKDXXzjh43DmNylgVpQQ==\n")
262
-
263
- client2 = s3_blobstore(:encryption_key => "zzz",
264
- :bucket_name => "test",
265
- :access_key_id => "KEY",
266
- :secret_access_key => "SECRET")
267
-
268
- File.open(@from_path, "w") { |f| f.write(File.read(@to_path)) }
269
- File.open(@from_path, "r") do |from|
270
- File.open(@to_path, "w") do |to|
271
- lambda {
272
- client2.send(:decrypt_stream, from, to)
273
- }.should raise_error(Bosh::Blobstore::BlobstoreError, "Decryption error: bad decrypt")
274
- end
275
- end
276
- end
277
-
278
- end
279
-
280
- end
281
-
282
- end