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