aws-s3 0.2.1 → 0.3.0

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.
@@ -39,35 +39,6 @@ module AWS
39
39
  end
40
40
  end
41
41
  end
42
-
43
- class CoercibleString < String
44
- attr_accessor :generator
45
- class << self
46
- def coerce(string)
47
- new(string).coerce
48
- end
49
- end
50
-
51
- def coerce
52
- case self
53
- when 'true': true
54
- when 'false': false
55
- when /^\d+$/: Integer(self)
56
- when datetime_format: Time.parse(self)
57
- else
58
- self
59
- end
60
- end
61
-
62
- private
63
-
64
- # Lame hack since Date._parse is so accepting. S3 dates are of the form: '2006-10-29T23:14:47.000Z'
65
- # so unless the string looks like that, don't even try, otherwise it might convert an object's
66
- # key from something like '03 1-2-3-Apple-Tree.mp3' to Sat Feb 03 00:00:00 CST 2001.
67
- def datetime_format
68
- /^\d{4}-\d{2}-\d{2}\w\d{2}:\d{2}:\d{2}/
69
- end
70
- end
71
42
 
72
43
  class XmlParser < Hash
73
44
  include Typecasting
@@ -57,7 +57,7 @@ module AWS
57
57
  memoized :parsed
58
58
 
59
59
  def inspect
60
- "#<#{self.class}:0x#{object_id} #{response.code} #{response.message}>"
60
+ "#<%s:0x%s %s %s>" % [self.class, object_id, response.code, response.message]
61
61
  end
62
62
  end
63
63
  end
@@ -119,7 +119,7 @@ module AWS
119
119
  end
120
120
 
121
121
  def inspect
122
- "#<#{self.class.name}:0x#{object_id} #{response.code} #{error.code}: '#{error.message}'>"
122
+ "#<%s:0x%s %s %s: '%s'>" % [self.class.name, object_id, response.code, error.code, error.message]
123
123
  end
124
124
  end
125
125
  end
@@ -2,8 +2,8 @@ module AWS
2
2
  module S3
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = '0'
5
- MINOR = '2'
6
- TINY = '1'
5
+ MINOR = '3'
6
+ TINY = '0'
7
7
  BETA = nil # Time.now.to_i.to_s
8
8
  end
9
9
 
@@ -37,7 +37,7 @@ class FasterXmlSimple
37
37
  end
38
38
 
39
39
  def out
40
- {doc.root.name => collapse(doc.root, doc.root.name)}
40
+ {doc.root.name => collapse(doc.root)}
41
41
  end
42
42
 
43
43
  private
@@ -45,14 +45,17 @@ class FasterXmlSimple
45
45
  {'contentkey' => '__content__', 'forcearray' => []}
46
46
  end
47
47
 
48
- def collapse(element, key_name)
48
+ def collapse(element)
49
49
  result = hash_of_attributes(element)
50
50
  if text_node? element
51
51
  text = collapse_text(element)
52
52
  result.merge!(content_key => text) if text =~ /\S/
53
53
  elsif element.children?
54
54
  element.inject(result) do |hash, child|
55
- (hash[child.name] ||= []) << collapse(child, element.name) unless child.text?
55
+ unless child.text?
56
+ child_result = collapse(child)
57
+ (hash[child.name] ||= []) << child_result
58
+ end
56
59
  hash
57
60
  end
58
61
  end
@@ -61,15 +64,14 @@ class FasterXmlSimple
61
64
  end
62
65
  # Compact them to ensure it complies with the user's requests
63
66
  inline_single_element_arrays(result)
64
- suppress_empty(result) if suppress_empty?
65
-
67
+ suppress_empty_content(result) unless force_content?
68
+ remove_empty_elements(result) if suppress_empty?
69
+
66
70
  result
67
71
  end
68
72
 
69
73
  def empty_element
70
- if options['suppressempty'] == true
71
- raise 'unimplemented'
72
- elsif !options.has_key? 'suppressempty'
74
+ if !options.has_key? 'suppressempty'
73
75
  {}
74
76
  else
75
77
  options['suppressempty']
@@ -92,12 +94,26 @@ class FasterXmlSimple
92
94
  end
93
95
  end
94
96
 
95
- def suppress_empty(result)
97
+ def remove_empty_elements(result)
98
+ result.each do |key, value|
99
+ if value == empty_element
100
+ result.delete key
101
+ end
102
+ end
103
+ end
104
+
105
+ def suppress_empty?
106
+ options['suppressempty'] == true
107
+ end
108
+
109
+
110
+
111
+ def suppress_empty_content(result)
96
112
  result.delete content_key if result[content_key] !~ /\S/
97
113
  end
98
114
 
99
- def suppress_empty?
100
- options.has_key? 'suppressempty'
115
+ def force_content?
116
+ options['forcecontent']
101
117
  end
102
118
 
103
119
  # a text node is one with 1 or more child nodes which are
@@ -122,6 +138,9 @@ class FasterXmlSimple
122
138
  end
123
139
 
124
140
  def parse(string)
141
+ if string == ''
142
+ string = ' '
143
+ end
125
144
  XML::Parser.string(string).parse
126
145
  end
127
146
  end
@@ -1,7 +1,6 @@
1
- require 'faster_xml_simple'
2
- require 'test/unit'
1
+ require File.dirname(__FILE__) + '/test_helper'
3
2
 
4
- class RegressionTest < Test::Unit::TestCase
3
+ class RegressionTest < FasterXSTest
5
4
  def test_content_nil_regressions
6
5
  expected = {"asdf"=>{"jklsemicolon"=>{}}}
7
6
  assert_equal expected, FasterXmlSimple.xml_in("<asdf><jklsemicolon /></asdf>")
@@ -23,8 +22,15 @@ class RegressionTest < Test::Unit::TestCase
23
22
  assert_equal Hash.new, FasterXmlSimple.xml_in(str)["asdf"]["fdsa"]
24
23
  assert_nil FasterXmlSimple.xml_in(str, 'suppressempty'=>nil)["asdf"]["fdsa"]
25
24
  assert_equal '', FasterXmlSimple.xml_in(str, 'suppressempty'=>'')["asdf"]["fdsa"]
26
- # assert !FasterXmlSimple.xml_in(str, 'suppressempty'=>true)["asdf"].has_key?("fdsa")
25
+ assert !FasterXmlSimple.xml_in(str, 'suppressempty'=>true)["asdf"].has_key?("fdsa")
26
+ end
27
+
28
+ def test_empty_string_doesnt_crash
29
+ assert_raise(XML::Parser::ParseError) do
30
+ silence_stderr do
31
+ FasterXmlSimple.xml_in('')
32
+ end
33
+ end
27
34
  end
28
-
29
35
 
30
36
  end
@@ -0,0 +1,17 @@
1
+
2
+ require 'test/unit'
3
+ require 'faster_xml_simple'
4
+
5
+ class FasterXSTest < Test::Unit::TestCase
6
+ def default_test
7
+ end
8
+
9
+ def silence_stderr
10
+ str = STDERR.dup
11
+ STDERR.reopen("/dev/null")
12
+ STDERR.sync=true
13
+ yield
14
+ ensure
15
+ STDERR.reopen(str)
16
+ end
17
+ end
@@ -1,8 +1,7 @@
1
- require 'faster_xml_simple'
2
- require 'test/unit'
1
+ require File.dirname(__FILE__) + '/test_helper'
3
2
  require 'yaml'
4
3
 
5
- class XmlSimpleComparisonTest < Test::Unit::TestCase
4
+ class XmlSimpleComparisonTest < FasterXSTest
6
5
 
7
6
  # Define test methods
8
7
 
@@ -102,6 +102,17 @@ class PolicyTest < Test::Unit::TestCase
102
102
  assert_nil policy.grants.delete(non_grant)
103
103
  end
104
104
  end
105
+
106
+ def test_grant_list_comparison
107
+ policy = ACL::Policy.new
108
+ policy2 = ACL::Policy.new
109
+
110
+ grant_names = [:public_read, :public_read_acp, :authenticated_write]
111
+ grant_names.each {|grant_name| policy.grants << ACL::Grant.grant(grant_name)}
112
+ grant_names.reverse_each {|grant_name| policy2.grants << ACL::Grant.grant(grant_name)}
113
+
114
+ assert_equal policy.grants, policy2.grants
115
+ end
105
116
  end
106
117
 
107
118
  class GrantTest < Test::Unit::TestCase
@@ -123,7 +134,7 @@ class GrantTest < Test::Unit::TestCase
123
134
 
124
135
  grant = nil
125
136
  assert_nothing_raised do
126
- grant = ACL::Grant.grant :public_read
137
+ grant = ACL::Grant.grant(:public_read)
127
138
  end
128
139
 
129
140
  assert grant
@@ -240,4 +251,4 @@ class ACLOptionProcessorTest < Test::Unit::TestCase
240
251
  def acl(options)
241
252
  options['x-amz-acl']
242
253
  end
243
- end
254
+ end
@@ -27,6 +27,14 @@ class ConnectionTest < Test::Unit::TestCase
27
27
  assert_equal 'https://', connection.protocol
28
28
  end
29
29
 
30
+ def test_connection_is_persistent_by_default
31
+ connection = Connection.new(@keys)
32
+ assert connection.persistent?
33
+
34
+ connection = Connection.new(@keys.merge(:persistent => false))
35
+ assert !connection.persistent?
36
+ end
37
+
30
38
  def test_server_and_port_are_passed_onto_connection
31
39
  connection = Connection.new(@keys)
32
40
  options = connection.instance_variable_get('@options')
@@ -64,6 +64,37 @@ class StringExtensionsTest < Test::Unit::TestCase
64
64
  assert_equal after, before.to_header
65
65
  end
66
66
  end
67
+
68
+ def test_utf8?
69
+ assert !"318597/620065/GTL_75\24300_A600_A610.zip".utf8?
70
+ assert "318597/620065/GTL_75£00_A600_A610.zip".utf8?
71
+ end
72
+
73
+ def test_remove_extended
74
+ assert "318597/620065/GTL_75\24300_A600_A610.zip".remove_extended.utf8?
75
+ assert "318597/620065/GTL_75£00_A600_A610.zip".remove_extended.utf8?
76
+ end
77
+ end
78
+
79
+ class CoercibleStringTest < Test::Unit::TestCase
80
+
81
+ def test_coerce
82
+ coercions = [
83
+ ['1', 1],
84
+ ['false', false],
85
+ ['true', true],
86
+ ['2006-10-29T23:14:47.000Z', Time.parse('2006-10-29T23:14:47.000Z')],
87
+ ['Hello!', 'Hello!'],
88
+ ['false23', 'false23'],
89
+ ['03 1-2-3-Apple-Tree.mp3', '03 1-2-3-Apple-Tree.mp3']
90
+ ]
91
+
92
+ coercions.each do |before, after|
93
+ assert_nothing_raised do
94
+ assert_equal after, CoercibleString.coerce(before)
95
+ end
96
+ end
97
+ end
67
98
  end
68
99
 
69
100
  class KerneltExtensionsTest < Test::Unit::TestCase
@@ -122,6 +153,11 @@ class ModuleExtensionsTest < Test::Unit::TestCase
122
153
  Time.now
123
154
  end
124
155
  end
156
+
157
+ def quux
158
+ Time.now
159
+ end
160
+ memoized :quux
125
161
  end
126
162
 
127
163
  def setup
@@ -129,19 +165,38 @@ class ModuleExtensionsTest < Test::Unit::TestCase
129
165
  end
130
166
 
131
167
  def test_memoize
168
+ assert !@instance.instance_variables.include?('@foo')
132
169
  cached_result = @instance.foo
133
170
  assert_equal cached_result, @instance.foo
171
+ assert @instance.instance_variables.include?('@foo')
134
172
  assert_equal cached_result, @instance.send(:instance_variable_get, :@foo)
135
- assert_not_equal cached_result, @instance.foo(:reload)
173
+ assert_not_equal cached_result, new_cache = @instance.foo(:reload)
174
+ assert_equal new_cache, @instance.foo
175
+ assert_equal new_cache, @instance.send(:instance_variable_get, :@foo)
136
176
  end
137
177
 
138
- def test_customizing_storage
178
+ def test_customizing_memoize_storage
179
+ assert !@instance.instance_variables.include?('@bar')
180
+ assert !@instance.instance_variables.include?('@baz')
139
181
  cached_result = @instance.bar
182
+ assert !@instance.instance_variables.include?('@bar')
183
+ assert @instance.instance_variables.include?('@baz')
140
184
  assert_equal cached_result, @instance.bar
141
185
  assert_equal cached_result, @instance.send(:instance_variable_get, :@baz)
142
186
  assert_nil @instance.send(:instance_variable_get, :@bar)
143
187
  end
144
188
 
189
+ def test_memoized
190
+ assert !@instance.instance_variables.include?('@quux')
191
+ cached_result = @instance.quux
192
+ assert_equal cached_result, @instance.quux
193
+ assert @instance.instance_variables.include?('@quux')
194
+ assert_equal cached_result, @instance.send(:instance_variable_get, :@quux)
195
+ assert_not_equal cached_result, new_cache = @instance.quux(:reload)
196
+ assert_equal new_cache, @instance.quux
197
+ assert_equal new_cache, @instance.send(:instance_variable_get, :@quux)
198
+ end
199
+
145
200
  def test_constant_setting
146
201
  some_module = Module.new
147
202
  assert !some_module.const_defined?(:FOO)
@@ -164,8 +219,6 @@ class ModuleExtensionsTest < Test::Unit::TestCase
164
219
  assert_equal 'bar', some_module::FOO
165
220
  assert_equal 'bar', some_module.foo
166
221
  end
167
-
168
-
169
222
  end
170
223
 
171
224
  class AttributeProxyTest < Test::Unit::TestCase
@@ -0,0 +1,5 @@
1
+ bucket_get:
2
+ "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [14/Nov/2006:06:36:48 +0000] 67.165.183.125 bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 8B5297D428A05432 REST.GET.BUCKET - \"GET /marcel HTTP/1.1\" 200 - 4534 - 398 395 \"-\" \"-\"\n"
3
+
4
+ browser_get:
5
+ "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [25/Nov/2006:06:26:23 +0000] 67.165.183.125 65a011a29cdf8ec533ec3d1ccaae921c 41521D07CA012312 REST.GET.OBJECT kiss.jpg \"GET /marcel/kiss.jpg HTTP/1.1\" 200 - 67748 67748 259 104 \"-\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\"\n"
@@ -0,0 +1,7 @@
1
+ simple_log:
2
+ - "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [14/Nov/2006:06:36:48 +0000] 67.165.183.125 bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 8B5297D428A05432 REST.GET.BUCKET - \"GET /marcel HTTP/1.1\" 200 - 4534 - 398 395 \"-\" \"-\"\n"
3
+ - "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [14/Nov/2006:06:38:58 +0000] 67.165.183.125 bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 8F6F3C4027849420 REST.GET.BUCKET - \"GET /marcel HTTP/1.1\" 200 - 4534 - 458 456 \"-\" \"-\"\n"
4
+
5
+ requests_from_a_browser:
6
+ - "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [25/Nov/2006:06:26:23 +0000] 67.165.183.125 65a011a29cdf8ec533ec3d1ccaae921c 41521D07CA012312 REST.GET.OBJECT kiss.jpg \"GET /marcel/kiss.jpg HTTP/1.1\" 200 - 67748 67748 259 104 \"-\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\"\n"
7
+ - "bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1 marcel [25/Nov/2006:06:26:27 +0000] 67.165.183.125 65a011a29cdf8ec533ec3d1ccaae921c 88629578AFDDD9B5 REST.GET.TORRENT kiss.jpg \"GET /marcel/kiss.jpg?torrent HTTP/1.1\" 200 - 215 - 379 - \"-\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\"\n"
@@ -27,10 +27,63 @@ class LoggingStatusReadingTest < Test::Unit::TestCase
27
27
  end
28
28
 
29
29
  class LoggingStatusWritingTest < LoggingStatusReadingTest
30
-
31
30
  def setup
32
31
  super
33
32
  @disabled = Logging::Status.new(Parsing::XmlParser.new(@disabled.to_xml))
34
33
  @enabled = Logging::Status.new(Parsing::XmlParser.new(@enabled.to_xml))
35
34
  end
35
+ end
36
+
37
+ class LogTest < Test::Unit::TestCase
38
+ def test_value_converted_to_log_lines
39
+ log_object = S3Object.new
40
+ log_object.value = Fixtures::Logs.simple_log.join
41
+ log = Logging::Log.new(log_object)
42
+ assert_nothing_raised do
43
+ log.lines
44
+ end
45
+
46
+ assert_equal 2, log.lines.size
47
+ assert_kind_of Logging::Log::Line, log.lines.first
48
+ assert_equal 'marcel', log.lines.first.bucket
49
+ end
50
+ end
51
+
52
+ class LogLineTest < Test::Unit::TestCase
53
+ def setup
54
+ @line = Logging::Log::Line.new(Fixtures::Loglines.bucket_get)
55
+ end
56
+
57
+ def test_field_accessors
58
+ expected_results = {
59
+ :owner => Owner.new('id' => 'bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1'),
60
+ :bucket => 'marcel',
61
+ :time => Time.parse('11/14/2006 06:36:48 +0000'),
62
+ :remote_ip => '67.165.183.125',
63
+ :request_id => '8B5297D428A05432',
64
+ :requestor => Owner.new('id' => 'bb2041a25975c3d4ce9775fe9e93e5b77a6a9fad97dc7e00686191f3790b13f1'),
65
+ :operation => 'REST.GET.BUCKET',
66
+ :key => nil,
67
+ :request_uri => 'GET /marcel HTTP/1.1',
68
+ :http_status => 200,
69
+ :error_code => nil,
70
+ :bytes_sent => 4534,
71
+ :object_size => nil,
72
+ :total_time => 398,
73
+ :turn_around_time => 395,
74
+ :referrer => nil,
75
+ :user_agent => nil
76
+ }
77
+
78
+ expected_results.each do |field, expected|
79
+ assert_equal expected, @line.send(field)
80
+ end
81
+
82
+ assert_equal expected_results, @line.attributes
83
+ end
84
+
85
+ def test_user_agent
86
+ line = Logging::Log::Line.new(Fixtures::Loglines.browser_get)
87
+ assert_equal 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0', line.user_agent
88
+ end
36
89
  end
@@ -105,6 +105,21 @@ class ObjectTest < Test::Unit::TestCase
105
105
  about = S3Object.about('foo', 'bar')
106
106
  assert_kind_of S3Object::About, about
107
107
  assert_equal headers, about
108
+
109
+ S3Object.request_returns :code => 404
110
+ assert_raises(NoSuchKey) do
111
+ S3Object.about('foo', 'bar')
112
+ end
113
+ end
114
+ end
115
+
116
+ def test_exists?
117
+ S3Object.in_test_mode do
118
+ S3Object.request_returns :code => 404
119
+ assert_equal false, S3Object.exists?('foo', 'bar')
120
+
121
+ S3Object.request_returns :code => 200
122
+ assert_equal true, S3Object.exists?('foo', 'bar')
108
123
  end
109
124
  end
110
125