swift_client 0.1.4 → 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.
- 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
|