aws-s3 0.2.1 → 0.3.0

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