waz-storage 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/waz-storage.rb CHANGED
@@ -1,4 +1,12 @@
1
- %w{time cgi base64 rexml/document rexml/xpath restclient hmac-sha2 net/http}.each(&method(:require))
1
+ require 'time'
2
+ require 'cgi'
3
+ require 'base64'
4
+ require 'rexml/document'
5
+ require 'rexml/xpath'
6
+ require 'restclient'
7
+ require 'hmac-sha2'
8
+ require 'net/http'
9
+
2
10
  app_files = File.expand_path(File.join(File.dirname(__FILE__), 'waz', 'storage', '*.rb'))
3
11
  Dir[app_files].each(&method(:load))
4
12
 
@@ -35,7 +35,7 @@ module WAZ
35
35
  end
36
36
  end
37
37
 
38
- attr_accessor :name, :url, :content_type, :snapshot_date
38
+ attr_accessor :name, :url, :content_type, :snapshot_date, :railsetag
39
39
 
40
40
  # Creates a new instance of the Blob object. This constructor is internally used by the Container
41
41
  # it's initialized thru a hash that's received as parameter. It has the following requirements:
@@ -49,6 +49,7 @@ module WAZ
49
49
  self.url = options[:url]
50
50
  self.content_type = options[:content_type]
51
51
  self.snapshot_date = options[:snapshot_date]
52
+ self.railsetag = options[:railsetag]
52
53
  end
53
54
 
54
55
  # Returns the blob properties from Windows Azure. This properties always come as HTTP Headers and they include standard headers like
@@ -145,7 +145,8 @@ module WAZ
145
145
  properties = self.class.service_instance.get_blob_properties("#{self.name}/#{blob_name}")
146
146
  return BlobObject.new(:name => blob_name,
147
147
  :url => self.class.service_instance.generate_request_uri("#{self.name}/#{blob_name}"),
148
- :content_type => properties[:content_type])
148
+ :content_type => properties[:content_type],
149
+ :railsetag => properties[:x_ms_meta_railsetag])
149
150
  rescue RestClient::ResourceNotFound
150
151
  return nil
151
152
  end
@@ -7,12 +7,12 @@ module WAZ
7
7
 
8
8
  # Creates a container on the current Windows Azure Storage account.
9
9
  def create_container(container_name)
10
- execute :put, container_name, {:restype => 'container'}, {:x_ms_version => '2009-09-19'}
10
+ execute :put, container_name, {:restype => 'container'}, {:x_ms_version => '2011-08-18'}
11
11
  end
12
12
 
13
13
  # Retrieves all the properties existing on the container.
14
14
  def get_container_properties(container_name)
15
- execute(:get, container_name, {:restype => 'container'}, {:x_ms_version => '2009-09-19'}).headers
15
+ execute(:get, container_name, {:restype => 'container'}, {:x_ms_version => '2011-08-18'}).headers
16
16
  end
17
17
 
18
18
  # Set the container properties (metadata).
@@ -20,14 +20,14 @@ module WAZ
20
20
  # Remember that custom properties should be named as :x_ms_meta_{propertyName} in order
21
21
  # to have Windows Azure to persist them.
22
22
  def set_container_properties(container_name, properties = {})
23
- execute :put, container_name, { :restype => 'container', :comp => 'metadata' }, properties.merge!({:x_ms_version => '2009-09-19'})
23
+ execute :put, container_name, { :restype => 'container', :comp => 'metadata' }, properties.merge!({:x_ms_version => '2011-08-18'})
24
24
  end
25
25
 
26
26
  # Retrieves the value of the :x_ms_prop_publicaccess header from the
27
27
  # container properties indicating whether the container is publicly
28
28
  # accessible or not.
29
29
  def get_container_acl(container_name)
30
- headers = execute(:get, container_name, { :restype => 'container', :comp => 'acl' }, {:x_ms_version => '2009-09-19'}).headers
30
+ headers = execute(:get, container_name, { :restype => 'container', :comp => 'acl' }, {:x_ms_version => '2011-08-18'}).headers
31
31
  headers[:x_ms_blob_public_access]
32
32
  end
33
33
 
@@ -37,7 +37,7 @@ module WAZ
37
37
  #
38
38
  # Default is _false_
39
39
  def set_container_acl(container_name, public_available = WAZ::Blobs::BlobSecurity::Private)
40
- publicity = {:x_ms_version => '2009-09-19' }
40
+ publicity = {:x_ms_version => '2011-08-18' }
41
41
  publicity[:x_ms_blob_public_access] = public_available unless public_available == WAZ::Blobs::BlobSecurity::Private
42
42
  execute :put, container_name, { :restype => 'container', :comp => 'acl' }, publicity
43
43
  end
@@ -57,12 +57,12 @@ module WAZ
57
57
 
58
58
  # Deletes the given container from the Windows Azure Storage account.
59
59
  def delete_container(container_name)
60
- execute :delete, container_name, {:restype => 'container'}, {:x_ms_version => '2009-09-19'}
60
+ execute :delete, container_name, {:restype => 'container'}, {:x_ms_version => '2011-08-18'}
61
61
  end
62
62
 
63
63
  # Lists all the blobs inside the given container.
64
64
  def list_blobs(container_name)
65
- content = execute(:get, container_name, { :restype => 'container', :comp => 'list'}, {:x_ms_version => '2009-09-19'})
65
+ content = execute(:get, container_name, { :restype => 'container', :comp => 'list'}, {:x_ms_version => '2011-08-18'})
66
66
  doc = REXML::Document.new(content)
67
67
  containers = []
68
68
  REXML::XPath.each(doc, '//Blob/') do |item|
@@ -82,7 +82,7 @@ module WAZ
82
82
  #
83
83
  # metadata is a hash that stores all the properties that you want to add to the blob when creating it.
84
84
  def put_blob(path, payload, content_type = "application/octet-stream", metadata = {})
85
- default_headers = {"Content-Type" => content_type, :x_ms_version => "2009-09-19", :x_ms_blob_type => "BlockBlob"}
85
+ default_headers = {"Content-Type" => content_type, :x_ms_version => "2011-08-18", :x_ms_blob_type => "BlockBlob", :x_ms_meta_railsetag => Digest::MD5.hexdigest(payload)}
86
86
  execute :put, path, nil, metadata.merge(default_headers), payload
87
87
  end
88
88
 
@@ -94,38 +94,38 @@ module WAZ
94
94
  #
95
95
  # metadata is a hash that stores all the properties that you want to add to the blob when creating it.
96
96
  def put_block_list(path, blockids, content_type = "application/octet-stream", metadata = {})
97
- default_headers = {"Content-Type" => content_type, :x_ms_version => "2009-09-19"}
97
+ default_headers = {"Content-Type" => content_type, :x_ms_version => "2011-08-18"}
98
98
  execute :put, path, { :comp => 'blocklist' }, metadata.merge(default_headers), '<?xml version="1.0" encoding="utf-8"?><BlockList>' + blockids.map {|id| "<Latest>#{id.rstrip}</Latest>"}.join + '</BlockList>'
99
99
  end
100
100
 
101
101
  # Retrieves a blob (content + headers) from the current path.
102
102
  def get_blob(path, options = {})
103
- execute :get, path, options, {:x_ms_version => "2009-09-19"}
103
+ execute :get, path, options, {:x_ms_version => "2011-08-18"}
104
104
  end
105
105
 
106
106
  # Deletes the blob existing on the current path.
107
107
  def delete_blob(path)
108
- execute :delete, path, nil, {:x_ms_version => "2009-09-19"}
108
+ execute :delete, path, nil, {:x_ms_version => "2011-08-18"}
109
109
  end
110
110
 
111
111
  # Retrieves the properties associated with the blob at the given path.
112
112
  def get_blob_properties(path, options = {})
113
- execute(:head, path, options, {:x_ms_version => "2009-09-19"}).headers
113
+ execute(:head, path, options, {:x_ms_version => "2011-08-18"}).headers
114
114
  end
115
115
 
116
116
  # Sets the properties (metadata) associated to the blob at given path.
117
117
  def set_blob_properties(path, properties ={})
118
- execute :put, path, { :comp => 'properties' }, properties.merge({:x_ms_version => "2009-09-19"})
118
+ execute :put, path, { :comp => 'properties' }, properties.merge({:x_ms_version => "2011-08-18"})
119
119
  end
120
120
 
121
121
  # Set user defined metadata - overwrites any previous metadata key:value pairs
122
122
  def set_blob_metadata(path, metadata = {})
123
- execute :put, path, { :comp => 'metadata' }, metadata.merge({:x_ms_version => "2009-09-19"})
123
+ execute :put, path, { :comp => 'metadata' }, metadata.merge({:x_ms_version => "2011-08-18"})
124
124
  end
125
125
 
126
126
  # Copies a blob within the same account (not necessarily to the same container)
127
127
  def copy_blob(source_path, dest_path)
128
- execute :put, dest_path, nil, { :x_ms_version => "2009-09-19", :x_ms_copy_source => canonicalize_message(source_path) }
128
+ execute :put, dest_path, nil, { :x_ms_version => "2011-08-18", :x_ms_copy_source => canonicalize_message(source_path) }
129
129
  end
130
130
 
131
131
  # Adds a block to the block list of the given blob
@@ -149,7 +149,7 @@ module WAZ
149
149
 
150
150
  # Creates a read-only snapshot of a blob as it looked like in time.
151
151
  def snapshot_blob(path)
152
- execute(:put, path, { :comp => 'snapshot' }, {:x_ms_version => "2009-09-19"}).headers[:x_ms_snapshot]
152
+ execute(:put, path, { :comp => 'snapshot' }, {:x_ms_version => "2011-08-18"}).headers[:x_ms_snapshot]
153
153
  end
154
154
  end
155
155
  end
@@ -10,7 +10,7 @@ module WAZ
10
10
  # When the options :include => 'metadata' is passed it returns
11
11
  # the corresponding metadata for each queue on the listing.
12
12
  def list_queues(options ={})
13
- content = execute(:get, nil, { :comp => 'list' }.merge!(options), { :x_ms_version => "2009-09-19" })
13
+ content = execute(:get, nil, { :comp => 'list' }.merge!(options), { :x_ms_version => "2011-08-18" })
14
14
  doc = REXML::Document.new(content)
15
15
  queues = []
16
16
 
@@ -31,22 +31,22 @@ module WAZ
31
31
  # Creates a queue on the current storage account. Throws WAZ::Queues::QueueAlreadyExists when
32
32
  # existing metadata and given metadata differ.
33
33
  def create_queue(queue_name, metadata = {})
34
- execute(:put, queue_name, nil, metadata.merge!(:x_ms_version => '2009-09-19'))
34
+ execute(:put, queue_name, nil, metadata.merge!(:x_ms_version => '2011-08-18'))
35
35
  end
36
36
 
37
37
  # Deletes the given queue from the current storage account.
38
38
  def delete_queue(queue_name)
39
- execute(:delete, queue_name, {}, {:x_ms_version => '2009-09-19'})
39
+ execute(:delete, queue_name, {}, {:x_ms_version => '2011-08-18'})
40
40
  end
41
41
 
42
42
  # Gets the given queue metadata.
43
43
  def get_queue_metadata(queue_name)
44
- execute(:head, queue_name, { :comp => 'metadata'}, :x_ms_version => '2009-09-19').headers
44
+ execute(:head, queue_name, { :comp => 'metadata'}, :x_ms_version => '2011-08-18').headers
45
45
  end
46
46
 
47
47
  # Sets the given queue metadata.
48
48
  def set_queue_metadata(queue_name, metadata = {})
49
- execute(:put, queue_name, { :comp => 'metadata' }, metadata.merge!(:x_ms_version => '2009-09-19'))
49
+ execute(:put, queue_name, { :comp => 'metadata' }, metadata.merge!(:x_ms_version => '2011-08-18'))
50
50
  end
51
51
 
52
52
  # Enqueues a message on the current queue.
@@ -55,7 +55,7 @@ module WAZ
55
55
  # is omitted, the default time-to-live is 7 days.
56
56
  def enqueue(queue_name, message_payload, ttl = 604800)
57
57
  payload = "<?xml version=\"1.0\" encoding=\"utf-8\"?><QueueMessage><MessageText>#{message_payload}</MessageText></QueueMessage>"
58
- execute(:post, "#{queue_name}/messages", { :messagettl => ttl }, { 'Content-Type' => 'application/xml', :x_ms_version => "2009-09-19"}, payload)
58
+ execute(:post, "#{queue_name}/messages", { :messagettl => ttl }, { 'Content-Type' => 'application/xml', :x_ms_version => "2011-08-18"}, payload)
59
59
  end
60
60
 
61
61
  # Locks N messages (1 default) from the given queue.
@@ -66,7 +66,7 @@ module WAZ
66
66
  def get_messages(queue_name, options = {})
67
67
  raise WAZ::Queues::OptionOutOfRange, {:name => :num_of_messages, :min => 1, :max => 32} if (options.keys.include?(:num_of_messages) && (options[:num_of_messages].to_i < 1 || options[:num_of_messages].to_i > 32))
68
68
  raise WAZ::Queues::OptionOutOfRange, {:name => :visibility_timeout, :min => 1, :max => 7200} if (options.keys.include?(:visibility_timeout) && (options[:visibility_timeout].to_i < 1 || options[:visibility_timeout].to_i > 7200))
69
- content = execute(:get, "#{queue_name}/messages", options, {:x_ms_version => "2009-09-19"})
69
+ content = execute(:get, "#{queue_name}/messages", options, {:x_ms_version => "2011-08-18"})
70
70
  doc = REXML::Document.new(content)
71
71
  messages = []
72
72
  REXML::XPath.each(doc, '//QueueMessage/') do |item|
@@ -99,7 +99,7 @@ module WAZ
99
99
 
100
100
  # Marks every message on the given queue for deletion.
101
101
  def clear_queue(queue_name)
102
- execute :delete, "#{queue_name}/messages", {}, :x_ms_version => '2009-09-19'
102
+ execute :delete, "#{queue_name}/messages", {}, :x_ms_version => '2011-08-18'
103
103
  end
104
104
  end
105
105
  end
@@ -68,7 +68,7 @@ module WAZ
68
68
  # the canonicalized header line and the canonical form of the message, all of the joined by \n character. Encoded with
69
69
  # Base64 and encrypted with SHA256 using the access_key as the seed.
70
70
  def generate_signature(options = {})
71
- return generate_signature20090919(options) if options[:headers]["x-ms-version"] == "2009-09-19"
71
+ return generate_signature20090919(options) if options[:headers]["x-ms-version"] == "2011-08-18"
72
72
 
73
73
  signature = options[:method].to_s.upcase + "\x0A" +
74
74
  (options[:headers]["Content-MD5"] or "") + "\x0A" +
data/rakefile CHANGED
@@ -1,46 +1,16 @@
1
- require 'rake'
2
- require 'rubygems'
1
+ #!/usr/bin/env rake
3
2
  require 'rspec/core/rake_task'
4
- require 'rake/gempackagetask'
5
3
  require 'rake/rdoctask'
6
- require 'lib/waz-storage'
7
-
8
- task :default => [:specs]
4
+ require 'bundler/gem_tasks'
9
5
 
10
6
  RSpec::Core::RakeTask.new do |t|
11
7
  t.name = :specs
12
- t.pattern = "tests/**/*.rb"
8
+ t.pattern = "tests/**/*_test.rb"
13
9
  t.rcov = true
14
10
  t.rcov_opts = ['--text-report', '--exclude', "exclude.*/.gem,test,Library,#{ENV['GEM_HOME']}", '--sort', 'coverage' ]
15
11
  t.rspec_opts = ['-cfn']
16
12
  end
17
13
 
18
-
19
- namespace :dist do
20
- spec = Gem::Specification.new do |s|
21
- s.name = 'waz-storage'
22
- s.version = Gem::Version.new(WAZ::Storage::Version)
23
- s.summary = "Client library for Windows Azure's Storage Service REST API"
24
- s.description = "A simple implementation of Windows Azure Storage API for Ruby, inspired by the S3 gems and self experience of dealing with queues. The major goal of the whole gem is to enable ruby developers [like me =)] to leverage Windows Azure Storage features and have another option for cloud storage."
25
- s.email = 'johnny.halife@me.com'
26
- s.author = 'Johnny G. Halife'
27
- s.homepage = 'http://waz-storage.heroku.com'
28
- s.require_paths = ["lib"]
29
- s.files = FileList['rakefile', 'lib/**/*.rb']
30
- s.test_files = Dir['test/**/*']
31
- s.has_rdoc = true
32
- s.rdoc_options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
33
-
34
- # Dependencies
35
- s.add_dependency 'rest-client'
36
- s.add_dependency 'ruby-hmac'
37
- end
38
-
39
- Rake::GemPackageTask.new(spec) do |pkg|
40
- pkg.need_tar = true
41
- end
42
- end
43
-
44
14
  namespace :docs do
45
15
  Rake::RDocTask.new do |t|
46
16
  t.rdoc_dir = 'rdoc'
@@ -50,4 +20,4 @@ namespace :docs do
50
20
  t.rdoc_files.include('README.rdoc')
51
21
  t.rdoc_files.include('lib/**/*.rb')
52
22
  end
53
- end
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'rspec/autorun'
4
+ require 'mocha'
5
+ require 'restclient'
6
+ require 'time'
7
+ require 'hmac-sha2'
8
+ require 'base64'
9
+ require 'rexml/document'
10
+ require 'rexml/xpath'
11
+
12
+ RSpec.configure do |config|
13
+ config.mock_with :mocha
14
+ end
@@ -0,0 +1,80 @@
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'tests/configuration'
4
+ require 'lib/waz-blobs'
5
+
6
+ describe "Windows Azure Blobs interface API" do
7
+ it "should return blob path from url" do
8
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
9
+ blob.path.should == "container/blob"
10
+ end
11
+
12
+ it "should return blob metdata" do
13
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
14
+ WAZ::Blobs::Service.any_instance.expects(:get_blob_properties).with("container/blob").returns({:x_ms_meta_name => "blob_name"})
15
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
16
+ blob.metadata.should == { :x_ms_meta_name => "blob_name" }
17
+ end
18
+
19
+ it "should put blob metadataa" do
20
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
21
+ WAZ::Blobs::Service.any_instance.expects(:set_blob_properties).with("container/blob", {:x_ms_meta_name => "blob_name"})
22
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
23
+ blob.put_properties!({ :x_ms_meta_name => "blob_name" })
24
+ end
25
+
26
+ it "should get blob contents" do
27
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
28
+ WAZ::Blobs::Service.any_instance.expects(:get_blob).with("container/blob").returns("this is the blob content")
29
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
30
+ blob.value.should == "this is the blob content"
31
+ end
32
+
33
+ it "should put blob contents" do
34
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
35
+ WAZ::Blobs::Service.any_instance.expects(:get_blob_properties).with("container/blob").returns({})
36
+ WAZ::Blobs::Service.any_instance.expects(:put_blob).with("container/blob", "my new blob value", "application/xml", {}).returns("this is the blob content")
37
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
38
+ blob.value = "my new blob value"
39
+ end
40
+
41
+ it "should destroy blob" do
42
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
43
+ WAZ::Blobs::Service.any_instance.expects(:delete_blob).with("container/blob")
44
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "application/xml")
45
+ blob.destroy!
46
+ end
47
+
48
+ it "should copy blob" do
49
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
50
+ WAZ::Blobs::BlobObject.service_instance.expects(:copy_blob).with('container/blob', 'container/blob-copy')
51
+ WAZ::Blobs::BlobObject.service_instance.expects(:get_blob_properties).with('container/blob-copy').returns(:content_type => "plain/text")
52
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "plain/text")
53
+ copy = blob.copy('container/blob-copy')
54
+ copy.path.should == "container/blob-copy"
55
+ end
56
+
57
+ it "should take a snapshot of a blob" do
58
+ mock_time = Time.new
59
+ Time.stubs(:new).returns(mock_time)
60
+
61
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
62
+ WAZ::Blobs::BlobObject.service_instance.expects(:get_blob_properties).with('container/blob').returns(:content_type => "plain/text")
63
+ WAZ::Blobs::BlobObject.service_instance.expects(:snapshot_blob).with('container/blob').returns(mock_time.httpdate)
64
+
65
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "plain/text")
66
+ blob_snapshot = blob.snapshot
67
+ blob_snapshot.snapshot_date.should === mock_time.httpdate
68
+ end
69
+
70
+ it "should not allow snapshoted blobs to perform write operations" do
71
+ snapshot = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob", :content_type => "plain/text", :snapshot_date => Time.new.httpdate)
72
+ lambda { snapshot.value = "new-value" }.should raise_error(WAZ::Blobs::InvalidOperation)
73
+ lambda { snapshot.put_properties!({:x_ms_meta_name => "foo"}) }.should raise_error(WAZ::Blobs::InvalidOperation)
74
+ end
75
+
76
+ it "blob path should include snapshot parameter" do
77
+ blob = WAZ::Blobs::BlobObject.new(:name => "blob_name", :url => "http://localhost/container/blob?snapshot=foo", :content_type => "application/xml")
78
+ blob.path.should == "container/blob?snapshot=foo"
79
+ end
80
+ end
@@ -0,0 +1,162 @@
1
+ # enabling the load of files from root (on RSpec)
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../')
3
+ require 'tests/configuration'
4
+ require 'lib/waz-blobs'
5
+
6
+ describe "Windows Azure Containers interface API" do
7
+
8
+ it "should should throw when no container name is provided" do
9
+ lambda {WAZ::Blobs::Container.new}.should raise_error(WAZ::Storage::InvalidOption)
10
+ end
11
+
12
+ it "should list containers" do
13
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
14
+ WAZ::Blobs::Service.any_instance.expects(:list_containers).returns([{:name => 'my-container'}, {:name => 'other container'}])
15
+ containers = WAZ::Blobs::Container.list
16
+ containers.size.should == 2
17
+ containers.first().name.should == "my-container"
18
+ end
19
+
20
+ it "should be able to create a container" do
21
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
22
+ WAZ::Blobs::Service.any_instance.expects(:create_container).with("my-container")
23
+ container = WAZ::Blobs::Container.create('my-container')
24
+ container.name.should == 'my-container'
25
+ end
26
+
27
+ it "should be able to return a container by name" do
28
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
29
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:name => "container-name", :x_ms_meta_name => "container-name"}).twice
30
+ container = WAZ::Blobs::Container.find('container-name')
31
+ container.metadata[:x_ms_meta_name].should == 'container-name'
32
+ end
33
+
34
+ it "should be able to return container metadata" do
35
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
36
+ WAZ::Blobs::Service.any_instance.expects(:create_container).with("container-name")
37
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
38
+ container = WAZ::Blobs::Container.create('container-name')
39
+ container.metadata[:x_ms_meta_name].should == 'container-name'
40
+ end
41
+
42
+ it "should be able to say whether the container is public or not" do
43
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
44
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
45
+ WAZ::Blobs::Service.any_instance.expects(:get_container_acl).with("container-name").returns(false)
46
+ container = WAZ::Blobs::Container.find("container-name")
47
+ container.public_access?.should == false
48
+ end
49
+
50
+ it "should be able to set whether the container is public or not" do
51
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
52
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
53
+ WAZ::Blobs::Service.any_instance.expects(:set_container_acl).with('container-name', false)
54
+ container = WAZ::Blobs::Container.find("container-name")
55
+ container.public_access = false
56
+ end
57
+
58
+ it "should be able to set container properties" do
59
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
60
+ WAZ::Blobs::Service.any_instance.expects(:set_container_properties).with("container-name", {:x_ms_meta_meta1 => "meta1"}).returns(false)
61
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
62
+ container = WAZ::Blobs::Container.find("container-name")
63
+ container.put_properties!(:x_ms_meta_meta1 => "meta1")
64
+ end
65
+
66
+ it "should be able to return a list files within the container" do
67
+ expected_blobs = [ {:name => 'blob1', :url => 'url', :content_type => 'app/xml'}, {:name => 'blob2', :url => 'url', :content_type => 'app/xml'} ]
68
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
69
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
70
+ WAZ::Blobs::Service.any_instance.expects(:list_blobs).with("container-name").returns(expected_blobs)
71
+ container = WAZ::Blobs::Container.find("container-name")
72
+ container_blobs = container.blobs
73
+ container_blobs.first().name = expected_blobs[0][:name]
74
+ container_blobs[1].name = expected_blobs[1][:name]
75
+ end
76
+
77
+ it "should destroy container" do
78
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
79
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
80
+ WAZ::Blobs::Service.any_instance.expects(:delete_container).with("container-name")
81
+ container = WAZ::Blobs::Container.find("container-name")
82
+ container.destroy!
83
+ end
84
+
85
+ it "should be able to return null when container not found by name" do
86
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
87
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").raises(RestClient::ResourceNotFound)
88
+ container = WAZ::Blobs::Container.find('container-name')
89
+ container.nil?.should == true
90
+ end
91
+
92
+ it "should be able to put blob inside given container" do
93
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
94
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
95
+ WAZ::Blobs::Service.any_instance.expects(:put_blob).with("container-name/my_blob", "this is the blob content", "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
96
+ container = WAZ::Blobs::Container.find("container-name")
97
+ blob = container.store("my_blob", "this is the blob content", "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
98
+ blob.name.should == "my_blob"
99
+ blob.url.should == "http://my_account.blob.core.windows.net/container-name/my_blob"
100
+ blob.content_type.should == "text/plain; charset=UTF-8"
101
+ end
102
+
103
+ it "should be able to upload a stream to a blob inside a given container" do
104
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
105
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
106
+ WAZ::Blobs::Service.any_instance.expects(:put_block).with("container-name/my_blob", Base64.encode64('%064d' % 0), "this is the blob content")
107
+ WAZ::Blobs::Service.any_instance.expects(:put_block_list).with("container-name/my_blob", [Base64.encode64('%064d' % 0)], "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
108
+ container = WAZ::Blobs::Container.find("container-name")
109
+ blob = container.upload("my_blob", StringIO.new("this is the blob content"), "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
110
+ blob.name.should == "my_blob"
111
+ blob.url.should == "http://my_account.blob.core.windows.net/container-name/my_blob"
112
+ blob.content_type.should == "text/plain; charset=UTF-8"
113
+ end
114
+
115
+ it "should be able to put blob inside given container (when simulating fake containers)" do
116
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
117
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
118
+ WAZ::Blobs::Service.any_instance.expects(:put_blob).with("container-name/fake-container/blob", "this is the blob content", "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
119
+ container = WAZ::Blobs::Container.find("container-name")
120
+ blob = container.store("/fake-container/blob", "this is the blob content", "text/plain; charset=UTF-8", {:x_ms_meta_custom_property => "customValue"})
121
+ blob.name.should == "fake-container/blob"
122
+ blob.url.should == "http://my_account.blob.core.windows.net/container-name/fake-container/blob"
123
+ blob.content_type.should == "text/plain; charset=UTF-8"
124
+ end
125
+
126
+ it "should return a specific blob for the given container" do
127
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
128
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
129
+ WAZ::Blobs::Service.any_instance.expects(:get_blob_properties).with("container-name/my_blob").returns({ :content_type => "application/xml" })
130
+ container = WAZ::Blobs::Container.find("container-name")
131
+ blob = container['my_blob']
132
+ blob.name.should == 'my_blob'
133
+ blob.content_type.should == 'application/xml'
134
+ blob.url.should == 'http://my_account.blob.core.windows.net/container-name/my_blob'
135
+ end
136
+
137
+ it "should return nil when the file does not exist" do
138
+ WAZ::Storage::Base.stubs(:default_connection).returns({:account_name => "my_account", :access_key => "key"})
139
+ WAZ::Blobs::Service.any_instance.expects(:get_container_properties).with("container-name").returns({:x_ms_meta_name => "container-name"})
140
+ WAZ::Blobs::Service.any_instance.expects(:get_blob_properties).with("container-name/my_blob").raises(RestClient::ResourceNotFound)
141
+ container = WAZ::Blobs::Container.find('container-name')
142
+ blob = container['my_blob']
143
+ blob.nil?.should == true
144
+ end
145
+
146
+ it "should raise an exception when container name starts with - (hypen)" do
147
+ lambda { WAZ::Blobs::Container.create('-container') }.should raise_error(WAZ::Storage::InvalidParameterValue)
148
+ end
149
+
150
+ it "should raise an exception when container name ends with - (hypen)" do
151
+ lambda { WAZ::Blobs::Container.create('container-') }.should raise_error(WAZ::Storage::InvalidParameterValue)
152
+ end
153
+
154
+ it "should raise an exception when container name is less than 3" do
155
+ lambda { WAZ::Blobs::Container.create('co') }.should raise_error(WAZ::Storage::InvalidParameterValue)
156
+ end
157
+
158
+ it "should raise an exception when container name is longer than 63" do
159
+ lambda { WAZ::Blobs::Container.create('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') }.should raise_error(WAZ::Storage::InvalidParameterValue)
160
+ end
161
+
162
+ end