3scale_client 2.9.0 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fd79baa77606faea09171e9c577d1694c17ea5a
4
- data.tar.gz: 87ab11fd2aee6b31888ba5f22dcce546ee36d265
3
+ metadata.gz: a0c46a8b42107a91987d9861498f796287909fb5
4
+ data.tar.gz: 5d43b1ee44766fe2057fec8eea21f5a30a8ac83f
5
5
  SHA512:
6
- metadata.gz: 172557eb19d4c5bdca48c89e8a3d8785defdafc0300aac49d5d6692b9d32279fb78d5b059b8aea936cd1fa636ff62c4a559a11fdc06f88ffb79407f829d48845
7
- data.tar.gz: 631bea0687f9ae848ba1622ceb375edf27d82b039963651c8fb969e1a25e96ae350b27a21cb6f4bfa04155c851f15d5162e1de9c21cea77e32adf819f0518abc
6
+ metadata.gz: 1c3b09b26c8ec29367f68fc231b52c3d7af036d8360179b968d50d231a2a1332ba5b0c11139539e4af6a711cb2716fe47972eaa34e66fb4ba8addc29c876e33b
7
+ data.tar.gz: 3d3136b451d4694fc00291d013e07dd1fd562f4c605caf1bc32a7c4f1e5ca6c6bb9808eed46f54909d7e551fea5f7260363d6ef5c75aca9ef4f00b85f9d6c717
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [2.10.0] - 2016-11-25
5
+ ### Added
6
+ - Added support for 3scale extensions (experimental or non-standard
7
+ features that are not part of the official API). You just need to
8
+ add the `:extensions` symbol and the value to the hash of options that
9
+ the client methods accept. The value is itself a hash containing the
10
+ parameter names as keys and the parameter values as values.
11
+
4
12
  ## [2.9.0] - 2016-10-21
5
13
  This version drops support for Ruby versions < 2.1 and JRuby < 9.1.1.0.
6
14
 
data/lib/3scale/client.rb CHANGED
@@ -7,6 +7,7 @@ require '3scale/client/version'
7
7
 
8
8
  require '3scale/response'
9
9
  require '3scale/authorize_response'
10
+ require '3scale/rack_query'
10
11
 
11
12
  module ThreeScale
12
13
  Error = Class.new(RuntimeError)
@@ -47,6 +48,9 @@ module ThreeScale
47
48
  'def report(transactions: [], service_id: nil).'.freeze
48
49
  private_constant :DEPRECATION_MSG_OLD_REPORT
49
50
 
51
+ EXTENSIONS_HEADER = '3scale-options'.freeze
52
+ private_constant :EXTENSIONS_HEADER
53
+
50
54
  def initialize(options)
51
55
  if options[:provider_key].nil? || options[:provider_key] =~ /^\s*$/
52
56
  raise ArgumentError, 'missing :provider_key'
@@ -69,6 +73,7 @@ module ThreeScale
69
73
 
70
74
  options_usage = options.delete :usage
71
75
  options_log = options.delete :log
76
+ extensions = options.delete :extensions
72
77
 
73
78
  options.each_pair do |param, value|
74
79
  path += "&#{param}=#{CGI.escape(value.to_s)}"
@@ -86,7 +91,8 @@ module ThreeScale
86
91
  path += "&#{log.join('&')}"
87
92
  end
88
93
 
89
- http_response = @http.get(path)
94
+ headers = extensions_to_header extensions if extensions
95
+ http_response = @http.get(path, headers: headers)
90
96
 
91
97
  case http_response
92
98
  when Net::HTTPSuccess,Net::HTTPConflict
@@ -148,7 +154,7 @@ module ThreeScale
148
154
  # The signature of this method is a bit complicated because we decided to
149
155
  # keep backwards compatibility with a previous version of the method:
150
156
  # def report(*transactions)
151
- def report(*reports, transactions: [], service_id: nil, **rest)
157
+ def report(*reports, transactions: [], service_id: nil, extensions: nil, **rest)
152
158
  if (!transactions || transactions.empty?) && rest.empty?
153
159
  raise ArgumentError, 'no transactions to report'
154
160
  end
@@ -164,7 +170,8 @@ module ThreeScale
164
170
  payload['provider_key'] = CGI.escape(provider_key)
165
171
  payload['service_id'] = CGI.escape(service_id.to_s) if service_id
166
172
 
167
- http_response = @http.post('/transactions.xml', payload)
173
+ headers = extensions_to_header extensions if extensions
174
+ http_response = @http.post('/transactions.xml', payload, headers: headers)
168
175
 
169
176
  case http_response
170
177
  when Net::HTTPSuccess
@@ -189,6 +196,7 @@ module ThreeScale
189
196
  # usage:: predicted usage. It is optional. It is a hash where the keys are metrics
190
197
  # and the values their predicted usage.
191
198
  # Example: {'hits' => 1, 'my_metric' => 100}
199
+ # extensions:: Optional. Hash of extension keys and values.
192
200
  #
193
201
  # == Return
194
202
  #
@@ -210,9 +218,11 @@ module ThreeScale
210
218
  # end
211
219
  #
212
220
  def authorize(options)
221
+ extensions = options.delete :extensions
213
222
  path = "/transactions/authorize.xml" + options_to_params(options, ALL_PARAMS)
214
223
 
215
- http_response = @http.get(path)
224
+ headers = extensions_to_header extensions if extensions
225
+ http_response = @http.get(path, headers: headers)
216
226
 
217
227
  case http_response
218
228
  when Net::HTTPSuccess,Net::HTTPConflict
@@ -259,9 +269,11 @@ module ThreeScale
259
269
  # end
260
270
  #
261
271
  def oauth_authorize(options)
272
+ extensions = options.delete :extensions
262
273
  path = "/transactions/oauth_authorize.xml" + options_to_params(options, OAUTH_PARAMS)
263
274
 
264
- http_response = @http.get(path)
275
+ headers = extensions_to_header extensions if extensions
276
+ http_response = @http.get(path, headers: headers)
265
277
 
266
278
  case http_response
267
279
  when Net::HTTPSuccess,Net::HTTPConflict
@@ -275,10 +287,8 @@ module ThreeScale
275
287
 
276
288
  private
277
289
 
278
- # The support for the 'hierarchy' param is experimental. Its support is not
279
- # guaranteed for future versions.
280
- OAUTH_PARAMS = [:app_id, :app_key, :service_id, :redirect_url, :usage, :hierarchy]
281
- ALL_PARAMS = [:user_key, :app_id, :app_key, :service_id, :redirect_url, :usage, :hierarchy]
290
+ OAUTH_PARAMS = [:app_id, :app_key, :service_id, :redirect_url, :usage]
291
+ ALL_PARAMS = [:user_key, :app_id, :app_key, :service_id, :redirect_url, :usage]
282
292
  REPORT_PARAMS = [:user_key, :app_id, :service_id, :timestamp]
283
293
 
284
294
  def options_to_params(options, allowed_keys)
@@ -382,5 +392,10 @@ module ThreeScale
382
392
  response.error!(node.content.to_s.strip, node['code'].to_s.strip)
383
393
  response
384
394
  end
395
+
396
+ # Encode extensions header
397
+ def extensions_to_header(extensions)
398
+ { EXTENSIONS_HEADER => RackQuery.encode(extensions) }
399
+ end
385
400
  end
386
401
  end
@@ -39,20 +39,32 @@ module ThreeScale
39
39
  @port = port
40
40
  end
41
41
 
42
- def get_request(path)
42
+ def get_request(path, headers: nil)
43
43
  get = Net::HTTP::Get.new(path)
44
44
  get.add_field(*USER_CLIENT_HEADER)
45
45
  get.add_field('Host', @host)
46
+ add_request_headers(get, headers) if headers
46
47
  get
47
48
  end
48
49
 
49
- def post_request(path, payload)
50
+ def post_request(path, payload, headers: nil)
50
51
  post = Net::HTTP::Post.new(path)
51
52
  post.add_field(*USER_CLIENT_HEADER)
52
53
  post.add_field('Host', @host)
54
+ add_request_headers(post, headers) if headers
53
55
  post.set_form_data(payload)
54
56
  post
55
57
  end
58
+
59
+ private
60
+
61
+ def add_request_headers(req, headers)
62
+ if headers
63
+ headers.each do |hk, hv|
64
+ req.add_field(hk, hv)
65
+ end
66
+ end
67
+ end
56
68
  end
57
69
 
58
70
  class NetHttpPersistent < BaseClient
@@ -77,15 +89,15 @@ module ThreeScale
77
89
  @protocol = 'https'
78
90
  end
79
91
 
80
- def get(path)
92
+ def get(path, headers: nil)
81
93
  uri = full_uri(path)
82
- @http.request(uri, get_request(path))
94
+ @http.request(uri, get_request(path, headers: headers))
83
95
  end
84
96
 
85
97
 
86
- def post(path, payload)
98
+ def post(path, payload, headers: nil)
87
99
  uri = full_uri(path)
88
- @http.request(uri, post_request(path, payload))
100
+ @http.request(uri, post_request(path, payload, headers: headers))
89
101
  end
90
102
 
91
103
  def full_uri(path)
@@ -107,12 +119,12 @@ module ThreeScale
107
119
  @http.use_ssl = true
108
120
  end
109
121
 
110
- def get(path)
111
- @http.request get_request(path)
122
+ def get(path, headers: nil)
123
+ @http.request get_request(path, headers: headers)
112
124
  end
113
125
 
114
- def post(path, payload)
115
- @http.request post_request(path, payload)
126
+ def post(path, payload, headers: nil)
127
+ @http.request post_request(path, payload, headers: headers)
116
128
  end
117
129
  end
118
130
 
@@ -1,5 +1,5 @@
1
1
  module ThreeScale
2
2
  class Client
3
- VERSION = '2.9.0'
3
+ VERSION = '2.10.0'
4
4
  end
5
5
  end
@@ -0,0 +1,37 @@
1
+ # A simple module to encode hashes of param keys and values as expected by
2
+ # Rack in its nested queries parsing.
3
+ #
4
+ module RackQuery
5
+ class << self
6
+ def encode(hash)
7
+ hash.flat_map do |hk, hv|
8
+ encode_value(CGI.escape(hk.to_s), hv)
9
+ end.join('&'.freeze)
10
+ end
11
+
12
+ private
13
+
14
+ def encode_value(rack_param, val)
15
+ if val.is_a? Array
16
+ encode_array(rack_param, val)
17
+ elsif val.is_a? Hash
18
+ encode_hash(rack_param, val)
19
+ else
20
+ "#{rack_param}=#{CGI.escape(val.to_s)}"
21
+ end
22
+ end
23
+
24
+ def encode_array(rack_param, val)
25
+ rack_param = rack_param + '[]'
26
+ val.flat_map do |v|
27
+ encode_value(rack_param, v)
28
+ end
29
+ end
30
+
31
+ def encode_hash(rack_param, val)
32
+ val.flat_map do |k, v|
33
+ encode_value(rack_param + "[#{CGI.escape(k.to_s)}]", v)
34
+ end
35
+ end
36
+ end
37
+ end
data/test/client_test.rb CHANGED
@@ -267,7 +267,7 @@ class ThreeScale::ClientTest < MiniTest::Test
267
267
  # calls.
268
268
  urls = [:authorize, :authrep, :oauth_authorize].inject({}) do |acc, method|
269
269
  acc[method] = "http://#{@host}/transactions/#{method}.xml?"\
270
- "provider_key=1234abcd&app_id=foo&hierarchy=1"
270
+ "provider_key=1234abcd&app_id=foo"
271
271
  acc[method] << "&%5Busage%5D%5Bhits%5D=1" if method == :authrep
272
272
  acc
273
273
  end
@@ -317,7 +317,7 @@ class ThreeScale::ClientTest < MiniTest::Test
317
317
 
318
318
  urls.each do |method, url|
319
319
  FakeWeb.register_uri(:get, url, :status => ['200', 'OK'], :body => body)
320
- response = @client.send(method, :app_id => 'foo', :hierarchy => 1)
320
+ response = @client.send(method, :app_id => 'foo', extensions: { :hierarchy => 1 })
321
321
  assert_equal response.hierarchy, { 'parent1' => ['child1', 'child2'],
322
322
  'parent2' => ['child3'] }
323
323
  end
@@ -702,6 +702,65 @@ class ThreeScale::ClientTest < MiniTest::Test
702
702
  assert_equal "su1.3scale.net", request["host"]
703
703
  end
704
704
 
705
+ EXTENSIONS_HASH = {
706
+ 'a special &=key' => 'a special =&value',
707
+ 'ary' => [1,2],
708
+ 'a hash' => { one: 'one', two: 'two' },
709
+ 'combined' =>
710
+ { v: 'v', nested: [1, { h: [ { hh: [ { hhh: :deep }, 'val' ] } ], h2: :h2 } ] }
711
+ }
712
+ private_constant :EXTENSIONS_HASH
713
+ EXTENSIONS_STR = "a+special+%26%3Dkey=a+special+%3D%26value&ary[]=1&ary[]=2&" \
714
+ "a+hash[one]=one&a+hash[two]=two&combined[v]=v&" \
715
+ "combined[nested][]=1&combined[nested][][h][][hh][][hhh]=deep&" \
716
+ "combined[nested][][h][][hh][]=val&combined[nested][][h2]=h2".freeze
717
+ private_constant :EXTENSIONS_STR
718
+
719
+ def test_authorize_with_extensions
720
+ body = '<status>
721
+ <authorized>true</authorized>
722
+ <plan>Ultimate</plan>
723
+ </status>'
724
+ FakeWeb.register_uri(:get,
725
+ "http://#{@host}/transactions/authorize.xml?provider_key=1234abcd&app_id=foo",
726
+ :status => ['200', 'OK'], body: body)
727
+
728
+ @client.authorize(:app_id => 'foo', extensions: EXTENSIONS_HASH)
729
+
730
+ request = FakeWeb.last_request
731
+ assert_equal EXTENSIONS_STR, request[ThreeScale::Client.const_get('EXTENSIONS_HEADER')]
732
+ end
733
+
734
+ def test_authrep_with_extensions
735
+ body = '<status>
736
+ <authorized>true</authorized>
737
+ <plan>Ultimate</plan>
738
+ </status>'
739
+ FakeWeb.register_uri(:get,
740
+ "http://#{@host}/transactions/authrep.xml?provider_key=1234abcd&app_id=foo&%5Busage%5D%5Bhits%5D=1",
741
+ :status => ['200', 'OK'], body: body)
742
+
743
+ @client.authrep(:app_id => 'foo', extensions: EXTENSIONS_HASH)
744
+
745
+ request = FakeWeb.last_request
746
+ assert_equal EXTENSIONS_STR, request['3scale-options']
747
+ end
748
+
749
+ def test_report_with_extensions
750
+ FakeWeb.register_uri(:post, "http://#{@host}/transactions.xml",
751
+ :status => ['200', 'OK'])
752
+
753
+ transactions = [{ :app_id => 'app_id_1',
754
+ :usage => { 'hits' => 1 },
755
+ :timestamp => '2016-07-18 15:42:17 0200' }]
756
+
757
+ @client.report(transactions: transactions, service_id: 'a_service_id',
758
+ extensions: EXTENSIONS_HASH)
759
+
760
+ request = FakeWeb.last_request
761
+ assert_equal EXTENSIONS_STR, request['3scale-options']
762
+ end
763
+
705
764
  private
706
765
 
707
766
  #OPTIMIZE this tricky test helper relies on fakeweb catching the urls requested by the client
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: 3scale_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.0
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Cichra
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2016-10-21 00:00:00.000000000 Z
15
+ date: 2016-11-25 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bundler
@@ -172,13 +172,13 @@ files:
172
172
  - LICENCE
173
173
  - README.md
174
174
  - Rakefile
175
- - VERSION
176
175
  - gemfiles/rack_1.gemfile
177
176
  - lib/3scale/authorize_response.rb
178
177
  - lib/3scale/client.rb
179
178
  - lib/3scale/client/http_client.rb
180
179
  - lib/3scale/client/version.rb
181
180
  - lib/3scale/middleware.rb
181
+ - lib/3scale/rack_query.rb
182
182
  - lib/3scale/response.rb
183
183
  - lib/3scale_client.rb
184
184
  - test/benchmark.rb
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 2.8.2