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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cb7d0291c3fcc0d03fd4aa4711c8c7c4a06b46bf
4
- data.tar.gz: 8caa6d7f8e4e21ce1567f7d968e6197fd83760f4
2
+ SHA256:
3
+ metadata.gz: 9703134ee4b5656b16c32f49305288723eb7f66d6942c2f6392ac9f663803c96
4
+ data.tar.gz: 8f97e98bc8c83e549e4359b53891e0d12b4673a8990426704658a3c78289e546
5
5
  SHA512:
6
- metadata.gz: 88d70e38c7d901e1625c03d12e7a9e016f7d26a3687c1ad3282cc7c29847a3cdfc168ce275453cfd69aff8e27a7ece108c25d2438c3e989beae693d8c17688dd
7
- data.tar.gz: eada405a14079e11075ba3a378461c2975da0ef2107609dcf706dca2373da5fde6eea263376873bab01455e38d84d2dd512feacc9a15b84c9395ef55ae0b2bbc
6
+ metadata.gz: b06d3358d7d40de924ccdaff5e1de219e1d4882ea5e607f9d9fdff47b260ce57338dbdc92d19f80c5b9908257d3397ca37b6ab38e6a0353ead8f63124e983659
7
+ data.tar.gz: 1c5fa028f57c0f460d4f4a28b52534033cf4045212ba64df9bd32d58fa2291377a81d5b815249b79e51db71c526405123b23991e94c09daeed2043bb2c9ee624
data/.gitignore CHANGED
@@ -12,3 +12,4 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
+ .ruby-version
@@ -1,9 +1,8 @@
1
1
 
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.7
6
- - 2.2.3
3
+ - 2.1.10
4
+ - 2.2.5
5
+ - 2.3.1
7
6
 
8
7
  install:
9
8
  - "travis_retry bundle install"
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 -> HTTParty::Response
130
- * post_account(headers = {}) -> HTTParty::Response
131
- * head_containers -> HTTParty::Response
132
- * get_containers(query = {}) -> HTTParty::Response
133
- * paginate_containers(query = {}) -> Enumerator
134
- * get_container(container_name, query = {}) -> HTTParty::Response
135
- * paginate_container(container_name, query = {}) -> Enumerator
136
- * head_container(container_name) -> HTTParty::Response
137
- * put_container(container_name, headers = {}) -> HTTParty::Response
138
- * post_container(container_name, headers = {}) -> HTTParty::Response
139
- * delete_container(container_name) -> HTTParty::Response
140
- * put_object(object_name, data_or_io, container_name, headers = {}) -> HTTParty::Response
141
- * post_object(object_name, container_name, headers = {}) -> HTTParty::Response
142
- * get_object(object_name, container_name) -> HTTParty::Response
143
- * head_object(object_name, container_name) -> HTTParty::Response
144
- * delete_object(object_name, container_name) -> HTTParty::Response
145
- * get_objects(container_name, query = {}) -> HTTParty::Response
146
- * paginate_objects(container_name, query = {}) -> Enumerator
147
- * public_url(object_name, container_name) -> HTTParty::Response
148
- * temp_url(object_name, container_name, options = {}) -> HTTParty::Response
149
- * bulk_delete(entries) -> entries
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/)
@@ -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 :get_containers, query, &block
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 :get_container, container_name, query, &block
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"] = "chunked"
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
- request :put, "/#{container_name}/#{object_name}", :body_stream => data_or_io.respond_to?(:read) ? data_or_io : StringIO.new(data_or_io), :headers => extended_headers
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 post_object(object_name, container_name, headers = {})
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 :post, "/#{container_name}/#{object_name}", :headers => headers
123
+ request(:get, "/#{container_name}/#{object_name}", options.merge(block ? { :stream_body => true } : {}), &block)
115
124
  end
116
125
 
117
- def get_object(object_name, container_name)
126
+ def head_object(object_name, container_name, options = {})
118
127
  raise(EmptyNameError) if object_name.empty? || container_name.empty?
119
128
 
120
- request :get, "/#{container_name}/#{object_name}"
129
+ request :head, "/#{container_name}/#{object_name}", options
121
130
  end
122
131
 
123
- def head_object(object_name, container_name)
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 :head, "/#{container_name}/#{object_name}"
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 :get_objects, container_name, query, &block
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"] = "application/json"
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
- swift_endpoints = swift_service["endpoints"].select { |endpoint| endpoint["interface"] == "public" }
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
-
@@ -1,5 +1,4 @@
1
1
 
2
2
  class SwiftClient
3
- VERSION = "0.1.4"
3
+ VERSION = "0.3.0"
4
4
  end
5
-
@@ -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", "< 3.0"
22
+ spec.add_dependency "mime-types"
23
23
 
24
24
  spec.add_development_dependency "bundler"
25
25
  spec.add_development_dependency "rake"
@@ -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
-
@@ -4,4 +4,4 @@ require "minitest"
4
4
  require "minitest/autorun"
5
5
  require "webmock/minitest"
6
6
  require "minitest/unit"
7
- require "mocha/mini_test"
7
+ require "mocha/minitest"
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.1.4
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: 2016-09-05 00:00:00.000000000 Z
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: '3.0'
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: '3.0'
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
- rubyforge_project:
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