s4 0.0.1 → 0.0.2
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 +1 -1
- data/lib/s4.rb +120 -39
- data/s4.gemspec +7 -7
- data/test/s4_test.rb +151 -0
- metadata +4 -6
- data/test/s3_test.rb +0 -108
data/Rakefile
CHANGED
data/lib/s4.rb
CHANGED
@@ -5,7 +5,7 @@ require "time"
|
|
5
5
|
|
6
6
|
# Simpler AWS S3 library
|
7
7
|
class S4
|
8
|
-
VERSION = "0.0.
|
8
|
+
VERSION = "0.0.2"
|
9
9
|
|
10
10
|
# sub-resource names which may appear in the query string and also must be
|
11
11
|
# signed against.
|
@@ -16,8 +16,42 @@ class S4
|
|
16
16
|
HeaderValues = %w( response-content-type response-content-language response-expires reponse-cache-control response-content-disposition response-content-encoding )
|
17
17
|
|
18
18
|
attr_reader :connection, :access_key_id, :secret_access_key, :bucket, :host
|
19
|
-
|
20
|
-
|
19
|
+
|
20
|
+
class << self
|
21
|
+
# Connect to an S3 bucket.
|
22
|
+
#
|
23
|
+
# Pass your S3 connection parameters as URL, or read from ENV["S3_URL"] if
|
24
|
+
# none is passed.
|
25
|
+
#
|
26
|
+
# S3_URL format is s3://<access key id>:<secret access key>@s3.amazonaws.com/<bucket>
|
27
|
+
#
|
28
|
+
# i.e.
|
29
|
+
# bucket = S4.connect #=> Connects to ENV["S3_URL"]
|
30
|
+
# bucket = S4.connect("s3://0PN5J17HBGZHT7JJ3X82:k3nL7gH3+PadhTEVn5EXAMPLE@s3.amazonaws.com/bucket")
|
31
|
+
def connect(s3_url=ENV["S3_URL"])
|
32
|
+
new(s3_url).tap do |s4|
|
33
|
+
s4.connect
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Create an S3 bucket.
|
38
|
+
#
|
39
|
+
# See #connect for S3_URL parameters.
|
40
|
+
#
|
41
|
+
# Will create the bucket on S3 and connect to it, or just connect if the
|
42
|
+
# bucket already exists and is owned by you.
|
43
|
+
#
|
44
|
+
# i.e.
|
45
|
+
# bucket = S4.create
|
46
|
+
def create(s3_url=ENV["S3_URL"])
|
47
|
+
new(s3_url).tap do |s4|
|
48
|
+
s4.create
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Initialize a new S3 bucket connection.
|
54
|
+
def initialize(s3_url=ENV["S3_URL"])
|
21
55
|
raise ArgumentError, "No S3 URL provided. You can set ENV['S3_URL'], too." if s3_url.nil? || s3_url.empty?
|
22
56
|
|
23
57
|
begin
|
@@ -27,23 +61,38 @@ class S4
|
|
27
61
|
raise e
|
28
62
|
end
|
29
63
|
|
30
|
-
@access_key_id
|
64
|
+
@access_key_id = url.user
|
31
65
|
@secret_access_key = URI.unescape(url.password || "")
|
32
|
-
@host
|
33
|
-
@bucket
|
66
|
+
@host = url.host
|
67
|
+
@bucket = url.path[1..-1]
|
34
68
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
69
|
+
|
70
|
+
# Connect to the S3 bucket.
|
71
|
+
#
|
72
|
+
# Since S3 doesn't really require a persistent connection this really just
|
73
|
+
# makes sure that it *can* connect (i.e. the bucket exists and you own it).
|
74
|
+
def connect
|
75
|
+
raise NoSuchBucket.new(bucket) if request(uri("/", query: "location")).nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
# Create the S3 bucket.
|
79
|
+
def create
|
80
|
+
uri = URI::HTTP.build(host: host, path: "/#{bucket}")
|
81
|
+
request uri, Net::HTTP::Put.new(uri.request_uri)
|
38
82
|
end
|
39
83
|
|
40
84
|
# Lower level object get which just yields the successful S3 response to the
|
41
85
|
# block. See #download if you want to simply copy a file from S3 to local.
|
42
86
|
def get(name, &block)
|
43
87
|
request(uri(name), &block)
|
88
|
+
rescue S4::Error => e
|
89
|
+
raise e if e.status != "404"
|
44
90
|
end
|
45
91
|
|
46
92
|
# Download the file with the given filename to the given destination.
|
93
|
+
#
|
94
|
+
# i.e.
|
95
|
+
# bucket.download("images/palm_trees.jpg", "./palm_trees.jpg")
|
47
96
|
def download(name, destination=nil)
|
48
97
|
get(name) do |response|
|
49
98
|
File.open(destination || File.join(Dir.pwd, File.basename(name)), "wb") do |io|
|
@@ -59,13 +108,18 @@ class S4
|
|
59
108
|
request(uri = uri(name), Net::HTTP::Delete.new(uri.request_uri))
|
60
109
|
end
|
61
110
|
|
62
|
-
# Upload the file with the given filename to the given destination in your
|
63
|
-
#
|
64
|
-
#
|
111
|
+
# Upload the file with the given filename to the given destination in your S3
|
112
|
+
# bucket.
|
113
|
+
#
|
114
|
+
# If no destination is given then uploads it with the same filename to the
|
115
|
+
# root of your bucket.
|
116
|
+
#
|
117
|
+
# i.e.
|
118
|
+
# bucket.upload("./images/1996_animated_explosion.gif", "website_background.gif")
|
65
119
|
def upload(name, destination=nil)
|
66
120
|
put File.open(name, "rb"), destination || File.basename(name)
|
67
121
|
end
|
68
|
-
|
122
|
+
|
69
123
|
def put(io, name)
|
70
124
|
uri = uri(name)
|
71
125
|
req = Net::HTTP::Put.new(uri.request_uri)
|
@@ -77,38 +131,40 @@ class S4
|
|
77
131
|
request(URI::HTTP.build(host: host, path: "/#{bucket}/#{name}"), req)
|
78
132
|
end
|
79
133
|
|
80
|
-
# List bucket contents
|
134
|
+
# List bucket contents.
|
135
|
+
#
|
136
|
+
# Optionally pass a prefix to list from (useful for paths).
|
137
|
+
#
|
138
|
+
# i.e.
|
139
|
+
# bucket.list("images/") #=> [ "birds.jpg", "bees.jpg" ]
|
81
140
|
def list(prefix = "")
|
82
141
|
REXML::Document.new(request(uri("", query: "prefix=#{prefix}"))).elements.collect("//Key", &:text)
|
83
142
|
end
|
84
|
-
|
143
|
+
|
85
144
|
private
|
86
|
-
|
145
|
+
|
146
|
+
def connection
|
147
|
+
@connection ||= Net::HTTP::Persistent.new("aws-s3/#{bucket}")
|
148
|
+
end
|
149
|
+
|
87
150
|
def uri(path, options={})
|
88
|
-
URI::HTTP.build(options.merge(host: host, path: "/#{bucket}/#{
|
151
|
+
URI::HTTP.build(options.merge(host: host, path: "/#{bucket}/#{URI.escape(path.sub(/^\//, ""))}"))
|
89
152
|
end
|
90
153
|
|
91
154
|
# Makes a request to the S3 API.
|
92
|
-
def request(uri, request
|
93
|
-
# TODO: Possibly use SAX parsing for large request bodies (?)
|
94
|
-
|
155
|
+
def request(uri, request=nil)
|
95
156
|
request ||= Net::HTTP::Get.new(uri.request_uri)
|
96
|
-
|
157
|
+
|
97
158
|
connection.request(uri, sign(uri, request)) do |response|
|
98
159
|
case response
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
when Net::HTTPSuccess
|
103
|
-
if block_given?
|
104
|
-
yield(response)
|
105
|
-
else
|
106
|
-
return response.body
|
107
|
-
end
|
108
|
-
|
160
|
+
when Net::HTTPSuccess
|
161
|
+
if block_given?
|
162
|
+
yield(response)
|
109
163
|
else
|
110
|
-
|
111
|
-
|
164
|
+
return response.body
|
165
|
+
end
|
166
|
+
else
|
167
|
+
raise Error.from_response(response)
|
112
168
|
end
|
113
169
|
end
|
114
170
|
end
|
@@ -123,22 +179,47 @@ class S4
|
|
123
179
|
end
|
124
180
|
|
125
181
|
def signature(uri, request)
|
182
|
+
query = signed_params(uri.query) if uri.query
|
183
|
+
|
126
184
|
Base64.encode64(
|
127
185
|
OpenSSL::HMAC.digest(
|
128
186
|
OpenSSL::Digest::Digest.new("sha1"),
|
129
187
|
secret_access_key,
|
130
|
-
"#{request.class::METHOD}\n\n#{request["Content-Type"]}\n#{request.fetch("Date")}\n
|
188
|
+
"#{request.class::METHOD}\n\n#{request["Content-Type"]}\n#{request.fetch("Date")}\n" + uri.path + (query ? "?#{query}" : "")
|
131
189
|
)
|
132
190
|
).chomp
|
133
191
|
end
|
134
|
-
|
192
|
+
|
193
|
+
# Returns the given query string consisting only of query parameters which
|
194
|
+
# need to be signed against, or nil if there are none in the query string.
|
195
|
+
def signed_params(query)
|
196
|
+
signed = query.
|
197
|
+
split("&").
|
198
|
+
collect{ |param| param.split("=") }.
|
199
|
+
reject{ |pair| !SubResources.include?(pair[0]) }.
|
200
|
+
collect{ |pair| pair.join("=") }.
|
201
|
+
join("&")
|
202
|
+
|
203
|
+
signed unless signed.empty?
|
204
|
+
end
|
205
|
+
|
135
206
|
# Base class of all S3 Errors
|
136
207
|
class Error < ::RuntimeError
|
137
|
-
|
138
|
-
|
208
|
+
attr_reader :code, :status
|
209
|
+
|
210
|
+
def self.from_response(response)
|
211
|
+
doc = REXML::Document.new(response.body).elements["//Error"]
|
139
212
|
code = doc.elements["Code"].text
|
140
213
|
message = doc.elements["Message"].text
|
141
|
-
|
214
|
+
|
215
|
+
new response.code, code, message
|
142
216
|
end
|
143
|
-
|
217
|
+
|
218
|
+
def initialize(status, code, message)
|
219
|
+
@status = status
|
220
|
+
@code = code
|
221
|
+
|
222
|
+
super "#{@code}: #{message}"
|
223
|
+
end
|
224
|
+
end
|
144
225
|
end
|
data/s4.gemspec
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require "./lib/s4"
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name
|
5
|
-
s.version
|
6
|
-
s.summary
|
7
|
-
s.description
|
8
|
-
s.authors
|
9
|
-
s.email
|
10
|
-
s.homepage
|
4
|
+
s.name = "s4"
|
5
|
+
s.version = S4::VERSION
|
6
|
+
s.summary = "Simple API for AWS S3"
|
7
|
+
s.description = "Simple API for AWS S3"
|
8
|
+
s.authors = ["Ben Alavi"]
|
9
|
+
s.email = ["ben.alavi@citrusbyte.com"]
|
10
|
+
s.homepage = "http://github.com/benalavi/s4"
|
11
11
|
|
12
12
|
s.files = Dir[
|
13
13
|
"LICENSE",
|
data/test/s4_test.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require "contest"
|
2
|
+
require "timecop"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
begin
|
6
|
+
require "ruby-debug"
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
|
+
require File.expand_path("../lib/s4", File.dirname(__FILE__))
|
11
|
+
|
12
|
+
def fixture(filename="")
|
13
|
+
File.join(File.dirname(__FILE__), "fixtures", filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def output(filename="")
|
17
|
+
File.join(File.dirname(__FILE__), "output", filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
NewBucket = "s4-bucketthatdoesntexist"
|
21
|
+
TestBucket = "s4-test-bucket"
|
22
|
+
|
23
|
+
class S4Test < Test::Unit::TestCase
|
24
|
+
setup do
|
25
|
+
FileUtils.rm_rf(output)
|
26
|
+
FileUtils.mkdir_p(output)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "connecting to S3" do
|
30
|
+
should "return connected bucket if can connect" do
|
31
|
+
s4 = S4.connect
|
32
|
+
end
|
33
|
+
|
34
|
+
should "raise error if cannot connect" do
|
35
|
+
`s3cmd rb 's3://#{NewBucket}' 2>&1`
|
36
|
+
|
37
|
+
assert_raise(S4::Error) do
|
38
|
+
S4.connect ENV["S3_URL"].sub(TestBucket, NewBucket)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when S3 errors occur" do
|
44
|
+
# foo is taken bucket, will cause 409 Conflict on create
|
45
|
+
|
46
|
+
should "raise on S3 errors" do
|
47
|
+
assert_raise(S4::Error) do
|
48
|
+
S4.create(ENV["S3_URL"].sub(TestBucket, "foo"))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
should "capture code of S3 error" do
|
53
|
+
begin
|
54
|
+
S4.create(ENV["S3_URL"].sub(TestBucket, "foo"))
|
55
|
+
rescue S4::Error => e
|
56
|
+
assert_equal "409", e.status
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "creating a bucket" do
|
62
|
+
setup do
|
63
|
+
`s3cmd rb 's3://#{NewBucket}' 2>&1`
|
64
|
+
end
|
65
|
+
|
66
|
+
should "create a bucket" do
|
67
|
+
assert_equal "ERROR: Bucket '#{NewBucket}' does not exist", `s3cmd ls 's3://#{NewBucket}' 2>&1`.chomp
|
68
|
+
s4 = S4.create ENV["S3_URL"].sub(TestBucket, NewBucket)
|
69
|
+
assert_equal "", `s3cmd ls 's3://#{NewBucket}' 2>&1`.chomp
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when connected" do
|
74
|
+
setup do
|
75
|
+
@s4 = S4.connect
|
76
|
+
end
|
77
|
+
|
78
|
+
should "download foo.txt" do
|
79
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/foo.txt`
|
80
|
+
@s4.download("foo.txt", output("foo.txt"))
|
81
|
+
|
82
|
+
assert_equal "abc123", File.read(output("foo.txt"))
|
83
|
+
end
|
84
|
+
|
85
|
+
should "not download non-existent files" do
|
86
|
+
`s3cmd del 's3://#{@s4.bucket}/foo.txt'`
|
87
|
+
@s4.download("foo.txt", output("foo.txt"))
|
88
|
+
|
89
|
+
assert !File.exists?(output("foo.txt"))
|
90
|
+
end
|
91
|
+
|
92
|
+
should "return false when downloading non-existent files" do
|
93
|
+
`s3cmd del 's3://#{@s4.bucket}/foo.txt'`
|
94
|
+
assert_equal nil, @s4.download("foo.txt", output("foo.txt"))
|
95
|
+
end
|
96
|
+
|
97
|
+
should "yield raw response from get of foo.txt" do
|
98
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/foo.txt`
|
99
|
+
|
100
|
+
@s4.get("foo.txt") do |response|
|
101
|
+
assert_equal "abc123", response.body
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
should "delete object" do
|
106
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/foo.txt`
|
107
|
+
@s4.get("foo.txt") { |response| assert_equal "abc123", response.body }
|
108
|
+
@s4.delete("foo.txt")
|
109
|
+
|
110
|
+
assert_equal nil, @s4.get("foo.txt")
|
111
|
+
end
|
112
|
+
|
113
|
+
should "return list of items in bucket" do
|
114
|
+
`s3cmd del 's3://#{@s4.bucket}/abc/*'`
|
115
|
+
`s3cmd del 's3://#{@s4.bucket}/boom.txt'`
|
116
|
+
`s3cmd del 's3://#{@s4.bucket}/foo\ bar+baz.txt'`
|
117
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/foo.txt`
|
118
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/bar.txt`
|
119
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/baz.txt`
|
120
|
+
|
121
|
+
assert_equal %w( bar.txt baz.txt foo.txt ), @s4.list
|
122
|
+
end
|
123
|
+
|
124
|
+
should "return list of keys starting with prefix" do
|
125
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/abc/bing.txt`
|
126
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/abc/bang.txt`
|
127
|
+
`s3cmd put #{fixture("foo.txt")} s3://#{@s4.bucket}/boom.txt`
|
128
|
+
|
129
|
+
assert_equal %w( abc/bang.txt abc/bing.txt ), @s4.list("abc/")
|
130
|
+
end
|
131
|
+
|
132
|
+
should "get content with special chars in it" do
|
133
|
+
`s3cmd put #{fixture("foo.txt")} 's3://#{@s4.bucket}/foo bar+baz.txt'`
|
134
|
+
|
135
|
+
@s4.get("foo bar+baz.txt") { |response| assert_equal "abc123", response.body }
|
136
|
+
end
|
137
|
+
|
138
|
+
should "upload foo.txt" do
|
139
|
+
`s3cmd del 's3://#{@s4.bucket}/foo.txt'`
|
140
|
+
@s4.upload(fixture("foo.txt"))
|
141
|
+
@s4.get("foo.txt") { |response| assert_equal "abc123", response.body }
|
142
|
+
end
|
143
|
+
|
144
|
+
should "bark when no URL is provided" do
|
145
|
+
assert_raise(ArgumentError) { S4.connect("") }
|
146
|
+
assert_raise(ArgumentError) { S4.connect(nil) }
|
147
|
+
|
148
|
+
assert_raise(URI::InvalidURIError) { S4.connect("s3://foo:bar/baz") }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: s4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ben Alavi
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-09-01 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: net-http-persistent
|
@@ -59,8 +58,7 @@ files:
|
|
59
58
|
- Rakefile
|
60
59
|
- lib/s4.rb
|
61
60
|
- s4.gemspec
|
62
|
-
- test/
|
63
|
-
has_rdoc: true
|
61
|
+
- test/s4_test.rb
|
64
62
|
homepage: http://github.com/benalavi/s4
|
65
63
|
licenses: []
|
66
64
|
|
@@ -84,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
82
|
requirements: []
|
85
83
|
|
86
84
|
rubyforge_project:
|
87
|
-
rubygems_version: 1.
|
85
|
+
rubygems_version: 1.8.10
|
88
86
|
signing_key:
|
89
87
|
specification_version: 3
|
90
88
|
summary: Simple API for AWS S3
|
data/test/s3_test.rb
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
require "cutest"
|
2
|
-
require "timecop"
|
3
|
-
require "fileutils"
|
4
|
-
|
5
|
-
begin
|
6
|
-
require "ruby-debug"
|
7
|
-
rescue LoadError
|
8
|
-
end
|
9
|
-
|
10
|
-
require File.expand_path("../lib/s3", File.dirname(__FILE__))
|
11
|
-
|
12
|
-
def fixture(filename="")
|
13
|
-
File.join(File.dirname(__FILE__), "fixtures", filename)
|
14
|
-
end
|
15
|
-
|
16
|
-
def output(filename="")
|
17
|
-
File.join(File.dirname(__FILE__), "output", filename)
|
18
|
-
end
|
19
|
-
|
20
|
-
Bucket = URI(ENV["S3_URL"]).path[1..-1]
|
21
|
-
|
22
|
-
scope do
|
23
|
-
setup do
|
24
|
-
FileUtils.rm_rf(output)
|
25
|
-
FileUtils.mkdir_p(output)
|
26
|
-
@s3 = S3.new
|
27
|
-
end
|
28
|
-
|
29
|
-
test "should download foo.txt" do
|
30
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/foo.txt`
|
31
|
-
@s3.download("foo.txt", output("foo.txt"))
|
32
|
-
|
33
|
-
assert_equal "abc123", File.read(output("foo.txt"))
|
34
|
-
end
|
35
|
-
|
36
|
-
test "should not download non-existent files" do
|
37
|
-
`s3cmd del 's3://#{Bucket}/foo.txt'`
|
38
|
-
@s3.download("foo.txt", output("foo.txt"))
|
39
|
-
|
40
|
-
assert !File.exists?(output("foo.txt"))
|
41
|
-
end
|
42
|
-
|
43
|
-
test "should yield raw response from get of foo.txt" do
|
44
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/foo.txt`
|
45
|
-
|
46
|
-
@s3.get("foo.txt") do |response|
|
47
|
-
assert_equal "abc123", response.body
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
test "should delete object" do
|
52
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/foo.txt`
|
53
|
-
@s3.get("foo.txt") { |response| assert_equal "abc123", response.body }
|
54
|
-
@s3.delete("foo.txt")
|
55
|
-
|
56
|
-
assert_equal nil, @s3.get("foo.txt")
|
57
|
-
end
|
58
|
-
|
59
|
-
test "should return list of items in bucket" do
|
60
|
-
`s3cmd del 's3://#{Bucket}/abc/*'`
|
61
|
-
`s3cmd del 's3://#{Bucket}/boom.txt'`
|
62
|
-
`s3cmd del 's3://#{Bucket}/foo\ bar+baz.txt'`
|
63
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/foo.txt`
|
64
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/bar.txt`
|
65
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/baz.txt`
|
66
|
-
|
67
|
-
assert_equal %w( bar.txt baz.txt foo.txt ), @s3.list
|
68
|
-
end
|
69
|
-
|
70
|
-
test "should return list of keys starting with prefix" do
|
71
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/abc/bing.txt`
|
72
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/abc/bang.txt`
|
73
|
-
`s3cmd put #{fixture("foo.txt")} s3://#{Bucket}/boom.txt`
|
74
|
-
|
75
|
-
assert_equal %w( abc/bang.txt abc/bing.txt ), @s3.list("abc/")
|
76
|
-
end
|
77
|
-
|
78
|
-
test "should get content with special chars in it" do
|
79
|
-
`s3cmd put #{fixture("foo.txt")} 's3://#{Bucket}/foo bar+baz.txt'`
|
80
|
-
|
81
|
-
@s3.get("foo bar+baz.txt") { |response| assert_equal "abc123", response.body }
|
82
|
-
end
|
83
|
-
|
84
|
-
test "should upload foo.txt" do
|
85
|
-
`s3cmd del 's3://#{Bucket}/foo.txt'`
|
86
|
-
|
87
|
-
s3 = S3.new
|
88
|
-
|
89
|
-
s3.upload(fixture("foo.txt"))
|
90
|
-
|
91
|
-
s3.get("foo.txt") { |response| assert_equal "abc123", response.body }
|
92
|
-
end
|
93
|
-
|
94
|
-
test "barks when no URL is provided" do
|
95
|
-
assert_raise(ArgumentError) { S3.new("") }
|
96
|
-
assert_raise(ArgumentError) { S3.new(nil) }
|
97
|
-
|
98
|
-
assert_raise(URI::InvalidURIError) { S3.new("s3://foo:bar/baz") }
|
99
|
-
end
|
100
|
-
|
101
|
-
test "raises on S3 errors" do
|
102
|
-
s3 = S3.new(ENV["S3_URL"].sub(/.@/, "@")) # Break the password
|
103
|
-
|
104
|
-
assert_raise(S3::Error) do
|
105
|
-
s3.upload(fixture("foo.txt"))
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|