swift_client 0.1.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +3 -4
- data/README.md +78 -22
- data/lib/swift_client.rb +57 -48
- data/lib/swift_client/version.rb +1 -2
- data/swift_client.gemspec +1 -1
- data/test/swift_client_test.rb +45 -1
- data/test/test_helper.rb +1 -1
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9703134ee4b5656b16c32f49305288723eb7f66d6942c2f6392ac9f663803c96
|
4
|
+
data.tar.gz: 8f97e98bc8c83e549e4359b53891e0d12b4673a8990426704658a3c78289e546
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b06d3358d7d40de924ccdaff5e1de219e1d4882ea5e607f9d9fdff47b260ce57338dbdc92d19f80c5b9908257d3397ca37b6ab38e6a0353ead8f63124e983659
|
7
|
+
data.tar.gz: 1c5fa028f57c0f460d4f4a28b52534033cf4045212ba64df9bd32d58fa2291377a81d5b815249b79e51db71c526405123b23991e94c09daeed2043bb2c9ee624
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -101,7 +101,8 @@ swift_client = SwiftClient.new(
|
|
101
101
|
:auth_url => "https://auth.example.com/v3",
|
102
102
|
:storage_url => "https://storage.example.com/v1/AUTH_account",
|
103
103
|
:user_id => "user id",
|
104
|
-
:password => "password"
|
104
|
+
:password => "password",
|
105
|
+
:interface => "internal"
|
105
106
|
)
|
106
107
|
|
107
108
|
# OR
|
@@ -126,33 +127,83 @@ access the response body and JSON response. Checkout the
|
|
126
127
|
|
127
128
|
SwiftClient offers the following requests:
|
128
129
|
|
129
|
-
* head_account
|
130
|
-
* post_account(headers = {})
|
131
|
-
* head_containers
|
132
|
-
* get_containers(query = {})
|
133
|
-
* paginate_containers(query = {})
|
134
|
-
* get_container(container_name, query = {})
|
135
|
-
* paginate_container(container_name, query = {})
|
136
|
-
* head_container(container_name)
|
137
|
-
* put_container(container_name, headers = {})
|
138
|
-
* post_container(container_name, headers = {})
|
139
|
-
* delete_container(container_name)
|
140
|
-
* put_object(object_name, data_or_io, container_name, headers = {})
|
141
|
-
* post_object(object_name, container_name, headers = {})
|
142
|
-
* get_object(object_name, container_name) -> HTTParty::Response
|
143
|
-
*
|
144
|
-
*
|
145
|
-
*
|
146
|
-
*
|
147
|
-
*
|
148
|
-
*
|
149
|
-
*
|
130
|
+
* `head_account(options = {}) # => HTTParty::Response`
|
131
|
+
* `post_account(headers = {}, options = {}) # => HTTParty::Response`
|
132
|
+
* `head_containers(options = {}) # => HTTParty::Response`
|
133
|
+
* `get_containers(query = {}, options = {}) # => HTTParty::Response`
|
134
|
+
* `paginate_containers(query = {}, options = {}) # => Enumerator`
|
135
|
+
* `get_container(container_name, query = {}, options = {}) # => HTTParty::Response`
|
136
|
+
* `paginate_container(container_name, query = {}, options = {}) # => Enumerator`
|
137
|
+
* `head_container(container_name, options = {}) # => HTTParty::Response`
|
138
|
+
* `put_container(container_name, headers = {}, options = {}) # => HTTParty::Response`
|
139
|
+
* `post_container(container_name, headers = {}, options = {}) # => HTTParty::Response`
|
140
|
+
* `delete_container(container_name, options = {}) # => HTTParty::Response`
|
141
|
+
* `put_object(object_name, data_or_io, container_name, headers = {}, options = {}) # => HTTParty::Response`
|
142
|
+
* `post_object(object_name, container_name, headers = {}, options = {}) # => HTTParty::Response`
|
143
|
+
* `get_object(object_name, container_name, options = {}) -> HTTParty::Response`
|
144
|
+
* `get_object(object_name, container_name, options = {}) { |chunk| save chunk } # => HTTParty::Response`
|
145
|
+
* `head_object(object_name, container_name, options = {}) # => HTTParty::Response`
|
146
|
+
* `delete_object(object_name, container_name, options = {}) # => HTTParty::Response`
|
147
|
+
* `get_objects(container_name, query = {}, options = {}) # => HTTParty::Response`
|
148
|
+
* `paginate_objects(container_name, query = {}, options = {}) # => Enumerator`
|
149
|
+
* `public_url(object_name, container_name) # => HTTParty::Response`
|
150
|
+
* `temp_url(object_name, container_name, options = {}) # => HTTParty::Response`
|
151
|
+
* `bulk_delete(entries, options = {}) # => entries`
|
152
|
+
* `post_head(object_name, container_name, _headers = {}, options = {}) # => HTTParty::Response`
|
153
|
+
|
154
|
+
By default, the client instructs the Swift server to return JSON via an HTTP Accept header; to disable this pass `:json => false` in `options`. The rest of the `options` are passed directly to the internal [HTTParty](https://rubygems.org/gems/httparty) client.
|
155
|
+
|
156
|
+
### Getting large objects
|
157
|
+
The `get_object` method with out a block is suitable for small objects that easily fit in memory. For larger objects, specify a block to process chunked data as it comes in.
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
File.open("/tmp/output", "wb") do |file_io|
|
161
|
+
swift_client.get_object("/large/object", "container") do |chunk|
|
162
|
+
file_io.write(chunk)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
## Re-Using/Sharing/Caching Auth Tokens
|
168
|
+
|
169
|
+
Certain OpenStack/Swift providers have limits in place regarding token
|
170
|
+
generation. To re-use auth tokens by caching them via memcached, install dalli
|
171
|
+
|
172
|
+
`gem install dalli`
|
173
|
+
|
174
|
+
and provide an instance of Dalli::Client to SwiftClient:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
swift_client = SwiftClient.new(
|
178
|
+
:auth_url => "https://example.com/auth/v1.0",
|
179
|
+
...
|
180
|
+
:cache_store => Dalli::Client.new
|
181
|
+
)
|
182
|
+
```
|
183
|
+
|
184
|
+
The cache key used to store the auth token will include all neccessary details
|
185
|
+
to ensure the auth token won't be used for a different swift account erroneously.
|
186
|
+
|
187
|
+
The cache implementation of SwiftClient is not restricted to memcached. To use
|
188
|
+
a different one, simply implement a driver for your favorite cache store. See
|
189
|
+
[null_cache.rb](https://github.com/mrkamel/swift_client/blob/master/lib/swift_client/null_cache.rb)
|
190
|
+
for more info.
|
150
191
|
|
151
192
|
## bulk_delete
|
152
193
|
|
153
194
|
Takes an array containing container_name/object_name entries.
|
154
195
|
Automatically slices and sends 1_000 items per request.
|
155
196
|
|
197
|
+
## Non-chunked uploads
|
198
|
+
|
199
|
+
By default files are uploaded in chunks and using a `Transfer-Encoding:
|
200
|
+
chunked` header. You can override this by passing a `Transfer-Encoding:
|
201
|
+
identity` header:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
put_object(object_name, data_or_io, container_name, "Transfer-Encoding" => "identity")
|
205
|
+
```
|
206
|
+
|
156
207
|
## Contributing
|
157
208
|
|
158
209
|
1. Fork it ( https://github.com/mrkamel/swift_client/fork )
|
@@ -160,3 +211,8 @@ Automatically slices and sends 1_000 items per request.
|
|
160
211
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
161
212
|
4. Push to the branch (`git push origin my-new-feature`)
|
162
213
|
5. Create a new Pull Request
|
214
|
+
|
215
|
+
## Semantic Versioning
|
216
|
+
|
217
|
+
Starting with version 0.2.0, SwiftClient uses Semantic Versioning:
|
218
|
+
[SemVer](http://semver.org/)
|
data/lib/swift_client.rb
CHANGED
@@ -37,61 +37,61 @@ class SwiftClient
|
|
37
37
|
authenticate
|
38
38
|
end
|
39
39
|
|
40
|
-
def head_account
|
41
|
-
request :head, "/"
|
40
|
+
def head_account(options = {})
|
41
|
+
request :head, "/", options
|
42
42
|
end
|
43
43
|
|
44
|
-
def post_account(headers = {})
|
45
|
-
request :post, "/", :headers => headers
|
44
|
+
def post_account(headers = {}, options = {})
|
45
|
+
request :post, "/", options.merge(:headers => headers)
|
46
46
|
end
|
47
47
|
|
48
|
-
def head_containers
|
49
|
-
request :head, "/"
|
48
|
+
def head_containers(options = {})
|
49
|
+
request :head, "/", options
|
50
50
|
end
|
51
51
|
|
52
|
-
def get_containers(query = {})
|
53
|
-
request :get, "/", :query => query
|
52
|
+
def get_containers(query = {}, options = {})
|
53
|
+
request :get, "/", options.merge(:query => query)
|
54
54
|
end
|
55
55
|
|
56
|
-
def paginate_containers(query = {}, &block)
|
57
|
-
paginate
|
56
|
+
def paginate_containers(query = {}, options = {}, &block)
|
57
|
+
paginate(:get_containers, query, options, &block)
|
58
58
|
end
|
59
59
|
|
60
|
-
def get_container(container_name, query = {})
|
60
|
+
def get_container(container_name, query = {}, options = {})
|
61
61
|
raise(EmptyNameError) if container_name.empty?
|
62
62
|
|
63
|
-
request :get, "/#{container_name}", :query => query
|
63
|
+
request :get, "/#{container_name}", options.merge(:query => query)
|
64
64
|
end
|
65
65
|
|
66
|
-
def paginate_container(container_name, query = {}, &block)
|
67
|
-
paginate
|
66
|
+
def paginate_container(container_name, query = {}, options = {}, &block)
|
67
|
+
paginate(:get_container, container_name, query, options, &block)
|
68
68
|
end
|
69
69
|
|
70
|
-
def head_container(container_name)
|
70
|
+
def head_container(container_name, options = {})
|
71
71
|
raise(EmptyNameError) if container_name.empty?
|
72
72
|
|
73
|
-
request :head, "/#{container_name}"
|
73
|
+
request :head, "/#{container_name}", options
|
74
74
|
end
|
75
75
|
|
76
|
-
def put_container(container_name, headers = {})
|
76
|
+
def put_container(container_name, headers = {}, options = {})
|
77
77
|
raise(EmptyNameError) if container_name.empty?
|
78
78
|
|
79
|
-
request :put, "/#{container_name}", :headers => headers
|
79
|
+
request :put, "/#{container_name}", options.merge(:headers => headers)
|
80
80
|
end
|
81
81
|
|
82
|
-
def post_container(container_name, headers = {})
|
82
|
+
def post_container(container_name, headers = {}, options = {})
|
83
83
|
raise(EmptyNameError) if container_name.empty?
|
84
84
|
|
85
|
-
request :post, "/#{container_name}", :headers => headers
|
85
|
+
request :post, "/#{container_name}", options.merge(:headers => headers)
|
86
86
|
end
|
87
87
|
|
88
|
-
def delete_container(container_name)
|
88
|
+
def delete_container(container_name, options = {})
|
89
89
|
raise(EmptyNameError) if container_name.empty?
|
90
90
|
|
91
|
-
request :delete, "/#{container_name}"
|
91
|
+
request :delete, "/#{container_name}", options
|
92
92
|
end
|
93
93
|
|
94
|
-
def put_object(object_name, data_or_io, container_name, headers = {})
|
94
|
+
def put_object(object_name, data_or_io, container_name, headers = {}, options = {})
|
95
95
|
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
96
96
|
|
97
97
|
mime_type = MIME::Types.of(object_name).first
|
@@ -103,43 +103,52 @@ class SwiftClient
|
|
103
103
|
extended_headers["Content-Type"] ||= "application/octet-stream"
|
104
104
|
end
|
105
105
|
|
106
|
-
extended_headers["Transfer-Encoding"]
|
106
|
+
if extended_headers["Transfer-Encoding"] == "identity"
|
107
|
+
request :put, "/#{container_name}/#{object_name}", options.merge(:body => data_or_io.respond_to?(:read) ? data_or_io.read : data_or_io, :headers => extended_headers)
|
108
|
+
else
|
109
|
+
extended_headers["Transfer-Encoding"] = "chunked"
|
110
|
+
request :put, "/#{container_name}/#{object_name}", options.merge(:body_stream => data_or_io.respond_to?(:read) ? data_or_io : StringIO.new(data_or_io), :headers => extended_headers)
|
111
|
+
end
|
112
|
+
end
|
107
113
|
|
108
|
-
|
114
|
+
def post_object(object_name, container_name, headers = {}, options = {})
|
115
|
+
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
116
|
+
|
117
|
+
request :post, "/#{container_name}/#{object_name}", options.merge(:headers => headers)
|
109
118
|
end
|
110
119
|
|
111
|
-
def
|
120
|
+
def get_object(object_name, container_name, options = {}, &block)
|
112
121
|
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
113
122
|
|
114
|
-
request
|
123
|
+
request(:get, "/#{container_name}/#{object_name}", options.merge(block ? { :stream_body => true } : {}), &block)
|
115
124
|
end
|
116
125
|
|
117
|
-
def
|
126
|
+
def head_object(object_name, container_name, options = {})
|
118
127
|
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
119
128
|
|
120
|
-
request :
|
129
|
+
request :head, "/#{container_name}/#{object_name}", options
|
121
130
|
end
|
122
131
|
|
123
|
-
def
|
132
|
+
def post_head(object_name, container_name, _headers = {}, options = {})
|
124
133
|
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
125
134
|
|
126
|
-
request :
|
135
|
+
request :post, "/#{container_name}/#{object_name}", options.merge(headers: _headers)
|
127
136
|
end
|
128
137
|
|
129
|
-
def delete_object(object_name, container_name)
|
138
|
+
def delete_object(object_name, container_name, options = {})
|
130
139
|
raise(EmptyNameError) if object_name.empty? || container_name.empty?
|
131
140
|
|
132
|
-
request :delete, "/#{container_name}/#{object_name}"
|
141
|
+
request :delete, "/#{container_name}/#{object_name}", options
|
133
142
|
end
|
134
143
|
|
135
|
-
def get_objects(container_name, query = {})
|
144
|
+
def get_objects(container_name, query = {}, options = {})
|
136
145
|
raise(EmptyNameError) if container_name.empty?
|
137
146
|
|
138
|
-
request :get, "/#{container_name}", :query => query
|
147
|
+
request :get, "/#{container_name}", options.merge(:query => query)
|
139
148
|
end
|
140
149
|
|
141
|
-
def paginate_objects(container_name, query = {}, &block)
|
142
|
-
paginate
|
150
|
+
def paginate_objects(container_name, query = {}, options = {}, &block)
|
151
|
+
paginate(:get_objects, container_name, query, options, &block)
|
143
152
|
end
|
144
153
|
|
145
154
|
def public_url(object_name, container_name)
|
@@ -160,9 +169,9 @@ class SwiftClient
|
|
160
169
|
"#{storage_url}/#{container_name}/#{object_name}?temp_url_sig=#{signature}&temp_url_expires=#{expires}"
|
161
170
|
end
|
162
171
|
|
163
|
-
def bulk_delete(items)
|
172
|
+
def bulk_delete(items, options = {})
|
164
173
|
items.each_slice(1_000) do |slice|
|
165
|
-
request :delete, "/?bulk-delete", :body => slice.join("\n"), :headers => { "Content-Type" => "text/plain" }
|
174
|
+
request :delete, "/?bulk-delete", options.merge(:body => slice.join("\n"), :headers => { "Content-Type" => "text/plain" })
|
166
175
|
end
|
167
176
|
|
168
177
|
items
|
@@ -183,21 +192,21 @@ class SwiftClient
|
|
183
192
|
headers.keys.detect { |k| k.downcase == key.downcase }
|
184
193
|
end
|
185
194
|
|
186
|
-
def request(method, path, opts = {})
|
195
|
+
def request(method, path, opts = {}, &block)
|
187
196
|
headers = (opts[:headers] || {}).dup
|
188
197
|
headers["X-Auth-Token"] = auth_token
|
189
|
-
headers["Accept"]
|
198
|
+
headers["Accept"] ||= "application/json" unless opts.delete(:json) == false
|
190
199
|
|
191
200
|
stream_pos = opts[:body_stream].pos if opts[:body_stream]
|
192
201
|
|
193
|
-
response = HTTParty.send(method, "#{storage_url}#{path}", opts.merge(:headers => headers))
|
202
|
+
response = HTTParty.send(method, "#{storage_url}#{path}", opts.merge(:headers => headers), &block)
|
194
203
|
|
195
204
|
if response.code == 401
|
196
205
|
authenticate
|
197
206
|
|
198
207
|
opts[:body_stream].pos = stream_pos if opts[:body_stream]
|
199
208
|
|
200
|
-
return request(method, path, opts)
|
209
|
+
return request(method, path, opts, &block)
|
201
210
|
end
|
202
211
|
|
203
212
|
raise(ResponseError.new(response.code, response.message)) unless response.success?
|
@@ -333,7 +342,8 @@ class SwiftClient
|
|
333
342
|
|
334
343
|
return unless swift_services.size == 1
|
335
344
|
|
336
|
-
|
345
|
+
interface = options[:interface] || "public"
|
346
|
+
swift_endpoints = swift_service["endpoints"].select { |endpoint| endpoint["interface"] == interface }
|
337
347
|
swift_endpoint = swift_endpoints.first
|
338
348
|
|
339
349
|
return unless swift_endpoints.size == 1
|
@@ -341,13 +351,13 @@ class SwiftClient
|
|
341
351
|
swift_endpoint["url"]
|
342
352
|
end
|
343
353
|
|
344
|
-
def paginate(method, *args, query)
|
345
|
-
return enum_for(:paginate, method, *args, query) unless block_given?
|
354
|
+
def paginate(method, *args, query, options)
|
355
|
+
return enum_for(:paginate, method, *args, query, options) unless block_given?
|
346
356
|
|
347
357
|
marker = nil
|
348
358
|
|
349
359
|
loop do
|
350
|
-
response = send(method, *args, marker ? query.merge(:marker => marker) : query)
|
360
|
+
response = send(method, *args, marker ? query.merge(:marker => marker) : query, options)
|
351
361
|
|
352
362
|
return if response.parsed_response.empty?
|
353
363
|
|
@@ -357,4 +367,3 @@ class SwiftClient
|
|
357
367
|
end
|
358
368
|
end
|
359
369
|
end
|
360
|
-
|
data/lib/swift_client/version.rb
CHANGED
data/swift_client.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "httparty"
|
22
|
-
spec.add_dependency "mime-types"
|
22
|
+
spec.add_dependency "mime-types"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler"
|
25
25
|
spec.add_development_dependency "rake"
|
data/test/swift_client_test.rb
CHANGED
@@ -77,6 +77,15 @@ class SwiftClientTest < MiniTest::Test
|
|
77
77
|
assert_equal "https://example.com/v1/AUTH_account", @swift_client.storage_url
|
78
78
|
end
|
79
79
|
|
80
|
+
def test_v3_authentication_storage_url_from_catalog_with_multiple_endpoints
|
81
|
+
stub_request(:post, "https://auth.example.com/v3/auth/tokens").with(:body => JSON.dump("auth" => { "identity" => { "methods" => ["password"], "password" => { "user" => { "name" => "username", "password" => "secret", "domain" => { "name" => "example.com" }}}}})).to_return(:status => 200, :body => JSON.dump("token" => { "catalog"=> [{ "type" => "object-store", "endpoints" => [{ "interface"=>"public", "url"=> "https://example.com/v1/AUTH_account" }, { "interface"=>"internal", "url"=> "https://example.com/v2/AUTH_account" }] }] }), :headers => { "X-Subject-Token" => "Token", "Content-Type" => "application/json" })
|
82
|
+
|
83
|
+
@swift_client = SwiftClient.new(:auth_url => "https://auth.example.com/v3", :username => "username", :user_domain => "example.com", :password => "secret", :interface => "internal")
|
84
|
+
|
85
|
+
assert_equal "Token", @swift_client.auth_token
|
86
|
+
assert_equal "https://example.com/v2/AUTH_account", @swift_client.storage_url
|
87
|
+
end
|
88
|
+
|
80
89
|
def test_v3_authentication_without_storage_url_and_multiple_swifts
|
81
90
|
stub_request(:post, "https://auth.example.com/v3/auth/tokens").with(:body => JSON.dump("auth" => { "identity" => { "methods" => ["password"], "password" => { "user" => { "name" => "username", "password" => "secret", "domain" => { "name" => "example.com" }}}}})).to_return(:status => 200, :body => JSON.dump("token" => { "catalog"=> [{ "type" => "object-store", "endpoints" => [{ "interface"=>"public", "url"=> "https://example.com/v1/AUTH_account" }] }, { "type" => "object-store", "endpoints" => [{ "interface"=>"public", "url"=> "https://example.com/v1/AUTH_account" }] }] }), :headers => { "X-Subject-Token" => "Token", "Content-Type" => "application/json" })
|
82
91
|
|
@@ -245,6 +254,12 @@ class SwiftClientTest < MiniTest::Test
|
|
245
254
|
assert_equal 201, @swift_client.put_object("object", "data", "container", "X-Object-Meta-Test" => "Test").code
|
246
255
|
end
|
247
256
|
|
257
|
+
def test_put_object_nonchunked
|
258
|
+
stub_request(:put, "https://example.com/v1/AUTH_account/container/object").with(:body => "data", :headers => { "Transfer-Encoding" => "identity", "Content-Type" => "application/octet-stream", "Accept" => "application/json", "X-Auth-Token" => "Token", "X-Object-Meta-Test" => "Test" }).to_return(:status => 201, :body => "", :headers => {})
|
259
|
+
|
260
|
+
assert_equal 201, @swift_client.put_object("object", "data", "container", "X-Object-Meta-Test" => "Test", "Transfer-Encoding" => "identity").code
|
261
|
+
end
|
262
|
+
|
248
263
|
def test_put_object_with_renewed_authorization
|
249
264
|
stub_request(:put, "https://example.com/v1/AUTH_account/container/object").with(:body => "data", :headers => { "Transfer-Encoding" => "chunked", "Content-Type" => "application/octet-stream", "Accept" => "application/json", "X-Auth-Token" => "Token" }).to_return({ :status => 401, :body => "", :headers => {}}, { :status => 201, :body => "", :headers => {}})
|
250
265
|
|
@@ -269,16 +284,38 @@ class SwiftClientTest < MiniTest::Test
|
|
269
284
|
assert_equal 201, @swift_client.put_object("object", StringIO.new("data"), "container", "X-Object-Meta-Test" => "Test").code
|
270
285
|
end
|
271
286
|
|
287
|
+
def test_put_object_with_io_nonchunked
|
288
|
+
stub_request(:put, "https://example.com/v1/AUTH_account/container/object").with(:body => "data", :headers => { "Transfer-Encoding" => "identity", "Accept" => "application/json", "X-Auth-Token" => "Token", "X-Object-Meta-Test" => "Test" }).to_return(:status => 201, :body => "", :headers => {})
|
289
|
+
|
290
|
+
assert_equal 201, @swift_client.put_object("object", StringIO.new("data"), "container", "X-Object-Meta-Test" => "Test", "Transfer-Encoding" => "identity").code
|
291
|
+
end
|
292
|
+
|
272
293
|
def test_post_object
|
273
294
|
stub_request(:post, "https://example.com/v1/AUTH_account/container/object").with(:headers => { "Accept" => "application/json", "X-Auth-Token" => "Token", "X-Object-Meta-Test" => "Test" }).to_return(:status => 201, :body => "", :headers => {})
|
274
295
|
|
275
296
|
assert_equal 201, @swift_client.post_object("object", "container", "X-Object-Meta-Test" => "Test").code
|
276
297
|
end
|
277
298
|
|
299
|
+
def test_post_head
|
300
|
+
stub_request(:post, 'https://example.com/v1/AUTH_account/container/object').with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => 'Token', 'X-Delete-At' => '1553524860' }).to_return(status: 201, body: '', headers: {})
|
301
|
+
|
302
|
+
assert_equal 201, @swift_client.post_head('object', 'container', 'X-Delete-At' => '1553524860').code
|
303
|
+
end
|
304
|
+
|
278
305
|
def test_get_object
|
279
306
|
stub_request(:get, "https://example.com/v1/AUTH_account/container/object").with(:headers => { "Accept" => "application/json", "X-Auth-Token" => "Token" }).to_return(:status => 200, :body => "Body", :headers => {})
|
307
|
+
block_res = 0
|
308
|
+
|
309
|
+
large_body = "Body" * 16384
|
310
|
+
stub_request(:get, "https://example.com/v1/AUTH_account/container/large_object").with(:headers => { "Accept" => "application/json", "X-Auth-Token" => "Token" }).to_return(:status => 200, :body => large_body, :headers => {})
|
280
311
|
|
281
312
|
assert_equal "Body", @swift_client.get_object("object", "container").body
|
313
|
+
|
314
|
+
@swift_client.get_object("large_object", "container") do |chunk|
|
315
|
+
block_res += chunk.length
|
316
|
+
end
|
317
|
+
|
318
|
+
assert_equal block_res, large_body.length
|
282
319
|
end
|
283
320
|
|
284
321
|
def test_head_object
|
@@ -304,6 +341,14 @@ class SwiftClientTest < MiniTest::Test
|
|
304
341
|
assert_equal objects, @swift_client.get_objects("container-1", :limit => 2, :marker => "object-2").parsed_response
|
305
342
|
end
|
306
343
|
|
344
|
+
def test_get_objects_no_json
|
345
|
+
response = "object-2\nobject-3\n"
|
346
|
+
|
347
|
+
stub_request(:get, "https://example.com/v1/AUTH_account/container-1?limit=2&marker=object-2").with(:headers => { "X-Auth-Token" => "Token" }).to_return(:status => 200, :body => response, :headers => { "Content-Type" => "text/html" })
|
348
|
+
|
349
|
+
assert_equal response, @swift_client.get_objects("container-1", { :limit => 2, :marker => "object-2" }, :json => false).body
|
350
|
+
end
|
351
|
+
|
307
352
|
def test_paginate_objects
|
308
353
|
objects = [
|
309
354
|
{ "hash" => "Hash", "last_modified" => "Last modified", "bytes" => 1, "name" => "object-1", "content_type" => "Content type" },
|
@@ -340,4 +385,3 @@ class SwiftClientTest < MiniTest::Test
|
|
340
385
|
assert @swift_client.temp_url("object", "container", :expires_in => 86400) =~ %r{https://example.com/v1/AUTH_account/container/object\?temp_url_sig=[a-f0-9]{40}&temp_url_expires=1086400}
|
341
386
|
end
|
342
387
|
end
|
343
|
-
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swift_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Vetter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: mime-types
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -146,8 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
146
|
- !ruby/object:Gem::Version
|
147
147
|
version: '0'
|
148
148
|
requirements: []
|
149
|
-
|
150
|
-
rubygems_version: 2.2.2
|
149
|
+
rubygems_version: 3.0.3
|
151
150
|
signing_key:
|
152
151
|
specification_version: 4
|
153
152
|
summary: Small but powerful client to interact with OpenStack Swift
|