apipie-bindings 0.0.15 → 0.0.16

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
2
  SHA1:
3
- metadata.gz: c2de238c0346625717ad8c455ad933a8f58915fe
4
- data.tar.gz: 480e111759cf1d88b9b002f447f68b4fcefce7e7
3
+ metadata.gz: aff06fcd62b11a1cd42115eed2dc44642d5f312f
4
+ data.tar.gz: 1752856687b077fb3f35af546d687364b94bc732
5
5
  SHA512:
6
- metadata.gz: e439a3315f55647319631390fe43411664fce48963c90baa44003302d656576553e773e634946e05c51e557aaa7705fce897ca7e0bb4d29e75fe33e9149f159c
7
- data.tar.gz: e172fec2517f748068ece02e9c41ee3b8efab1d1d6745349c5e8cc733553abc5d62795826d75af20910c298121c8975cbf89a31da98bb4c126a7d3226326b9c0
6
+ metadata.gz: b0201bb9a4bca428e4a49d8b706daa2873e8e0d3252189b40ceaee3254e42c963b2ea52770c88dfe1b08c82eb454d9cd5713be3a052f9e4b206a979a3e799490
7
+ data.tar.gz: 2d43831dea22be3f35fcb6d298fabe2c05699ccb6e5300c158926dd4cd42e17e4dcd5498da470462cf22bffaf79b3f43a5b151a9a6eacd298e89b50819edf3cb
data/doc/release_notes.md CHANGED
@@ -1,6 +1,14 @@
1
1
  Release notes
2
2
  =============
3
3
 
4
+ ### 0.0.16 (2016-03-08)
5
+ * Controll following redirection ([#37](https://github.com/Apipie/apipie-bindings/issues/37))
6
+ * Enable for mocking api calls with validations
7
+ * Log the server uri ([#36](https://github.com/Apipie/apipie-bindings/issues/36))
8
+ * build without sudo ([#40](https://github.com/Apipie/apipie-bindings/issues/40))
9
+ * Added clear credentials on error ([#12112](http://projects.theforeman.org/issues/12112))
10
+ * Added a function that enables removing credentials on need ([#12112](http://projects.theforeman.org/issues/12112))
11
+
4
12
  ### 0.0.15 (2015-09-21)
5
13
  * Make awesome_print optional ([#29](https://github.com/Apipie/apipie-bindings/issues/29))
6
14
 
@@ -2,7 +2,7 @@ module ApipieBindings
2
2
 
3
3
  class Action
4
4
 
5
- attr_reader :name
5
+ attr_reader :name, :resource
6
6
 
7
7
  def initialize(resource, name, api)
8
8
  @resource = resource
@@ -57,7 +57,7 @@ module ApipieBindings
57
57
 
58
58
  def validate!(parameters)
59
59
  errors = validate(params, parameters)
60
-
60
+
61
61
  missing_arguments, errors = errors.partition { |e| e.kind == :missing_argument }
62
62
  missing_arguments.map! { |e| e.argument }
63
63
  raise ApipieBindings::MissingArgumentsError.new(missing_arguments) unless missing_arguments.empty?
@@ -65,7 +65,7 @@ module ApipieBindings
65
65
  invalid_types, errors = errors.partition { |e| e.kind == :invalid_type }
66
66
  invalid_types.map! { |e| [e.argument, e.details] }
67
67
  raise ApipieBindings::InvalidArgumentTypesError.new(invalid_types) unless invalid_types.empty?
68
-
68
+
69
69
  errors.map! { |e| e.argument }
70
70
  raise ApipieBindings::ValidationError.new(errors) unless errors.empty?
71
71
  end
@@ -82,7 +82,7 @@ module ApipieBindings
82
82
  values.each do |param, value|
83
83
  param_description = params.find { |p| p.name == param.to_s }
84
84
  if param_description
85
-
85
+
86
86
  # nested?
87
87
  if !param_description.params.empty? && !value.nil?
88
88
  # array
@@ -8,7 +8,7 @@ module ApipieBindings
8
8
 
9
9
  class API
10
10
 
11
- attr_reader :apidoc_cache_name, :fake_responses, :language
11
+ attr_reader :apidoc_cache_name, :fake_responses, :language, :uri, :follow_redirects
12
12
  attr_writer :dry_run
13
13
 
14
14
  # Creates new API bindings instance
@@ -45,6 +45,8 @@ module ApipieBindings
45
45
  # *after* each API request
46
46
  # @option config [Object] :logger (Logger.new(STDERR)) custom logger class
47
47
  # @option config [Number] :timeout API request timeout in seconds
48
+ # @option config [Symbol] :follow_redirects (:default) Possible values are :always, :never and :default.
49
+ # The :default is to only redirect in GET and HEAD requests (RestClient default)
48
50
  # @param [Hash] options params that are passed to ResClient as-is
49
51
  # @raise [ApipieBindings::ConfigurationError] when no +:uri+ or +:apidoc_cache_dir+ is provided
50
52
  # @example connect to a server
@@ -65,6 +67,7 @@ module ApipieBindings
65
67
  @apidoc_cache_dir = config[:apidoc_cache_dir] || File.join(apidoc_cache_base_dir, @uri.tr(':/', '_'), "v#{@api_version}")
66
68
  @apidoc_cache_name = config[:apidoc_cache_name] || set_default_name
67
69
  @apidoc_authenticated = (config[:apidoc_authenticated].nil? ? true : config[:apidoc_authenticated])
70
+ @follow_redirects = config.fetch(:follow_redirects, :default)
68
71
  @dry_run = config[:dry_run] || false
69
72
  @aggressive_cache_checking = config[:aggressive_cache_checking] || false
70
73
  @fake_responses = config[:fake_responses] || {}
@@ -85,6 +88,7 @@ module ApipieBindings
85
88
  headers.merge!(options.delete(:headers)) unless options[:headers].nil?
86
89
 
87
90
  log.debug "Global headers: #{inspect_data(headers)}"
91
+ log.debug "Follow redirects: #{@follow_redirects.to_s}"
88
92
 
89
93
  @credentials = config[:credentials] if config[:credentials] && config[:credentials].respond_to?(:to_params)
90
94
 
@@ -109,6 +113,10 @@ module ApipieBindings
109
113
  end
110
114
  end
111
115
 
116
+ def clear_credentials
117
+ @client_with_auth = nil
118
+ @credentials.clear
119
+ end
112
120
 
113
121
  def apidoc
114
122
  @apidoc = @apidoc || load_apidoc || retrieve_apidoc
@@ -155,9 +163,14 @@ module ApipieBindings
155
163
  check_cache if @aggressive_cache_checking
156
164
  resource = resource(resource_name)
157
165
  action = resource.action(action_name)
158
- route = action.find_route(params)
159
166
  action.validate!(params) unless options[:skip_validation]
160
167
  options[:fake_response] = find_match(fake_responses, resource_name, action_name, params) || action.examples.first if dry_run?
168
+
169
+ call_action(action, params, headers, options)
170
+ end
171
+
172
+ def call_action(action, params={}, headers={}, options={})
173
+ route = action.find_route(params)
161
174
  return http_call(
162
175
  route.method,
163
176
  route.path(params),
@@ -192,6 +205,7 @@ module ApipieBindings
192
205
  headers[:params] = params if params
193
206
  end
194
207
 
208
+ log.info "Server: #{@uri}"
195
209
  log.info "#{http_method.to_s.upcase} #{path}"
196
210
  log.debug "Params: #{inspect_data(params)}"
197
211
  log.debug "Headers: #{inspect_data(headers)}"
@@ -201,13 +215,7 @@ module ApipieBindings
201
215
  if dry_run?
202
216
  empty_response = ApipieBindings::Example.new('', '', '', 200, '')
203
217
  ex = options[:fake_response ] || empty_response
204
- net_http_resp = Net::HTTPResponse.new(1.0, ex.status, "")
205
- if RestClient::Response.method(:create).arity == 4 # RestClient > 1.8.0
206
- response = RestClient::Response.create(ex.response, net_http_resp, args,
207
- RestClient::Request.new(:method=>http_method, :url=>path))
208
- else
209
- response = RestClient::Response.create(ex.response, net_http_resp, args)
210
- end
218
+ response = create_fake_response(ex.status, ex.response, http_method, path, args)
211
219
  else
212
220
  begin
213
221
  apidoc_without_auth = (path =~ /\/apidoc\//) && !@apidoc_authenticated
@@ -216,6 +224,7 @@ module ApipieBindings
216
224
  response = call_client(client, path, args)
217
225
  update_cache(response.headers[:apipie_checksum])
218
226
  rescue => e
227
+ clear_credentials if e.is_a? RestClient::Unauthorized
219
228
  log.debug e.message + "\n" +
220
229
  inspect_data(e.respond_to?(:response) ? process_data(e.response) : e)
221
230
  raise
@@ -282,7 +291,32 @@ module ApipieBindings
282
291
  private
283
292
 
284
293
  def call_client(client, path, args)
285
- client[path].send(*args)
294
+ block = rest_client_call_block
295
+ client[path].send(*args, &block)
296
+ end
297
+
298
+ def rest_client_call_block
299
+ Proc.new do |response, request, result, &block|
300
+ if [301, 302, 307].include?(response.code) && [:always, :never].include?(@follow_redirects)
301
+ if @follow_redirects == :always
302
+ log.debug "Response redirected to #{response.headers[:location]}"
303
+ response.follow_redirection(request, result, &block)
304
+ else
305
+ raise exception_with_response(response)
306
+ end
307
+ else
308
+ response.return!(request, result, &block)
309
+ end
310
+ end
311
+ end
312
+
313
+ def exception_with_response(response)
314
+ begin
315
+ klass = RestClient::Exceptions::EXCEPTIONS_MAP.fetch(response.code)
316
+ rescue KeyError
317
+ raise RestClient.RequestFailed.new(response, response.code)
318
+ end
319
+ raise klass.new(response, response.code)
286
320
  end
287
321
 
288
322
  def authenticated_client
@@ -348,5 +382,18 @@ module ApipieBindings
348
382
  def inspect_data(obj)
349
383
  ApipieBindings::Utils.inspect_data(obj)
350
384
  end
385
+
386
+ def create_fake_response(status, body, method, path, args={})
387
+ net_http_resp = Net::HTTPResponse.new(1.0, status, "")
388
+ if RestClient::Response.method(:create).arity == 4 # RestClient > 1.8.0
389
+ RestClient::Response.create(body, net_http_resp, args, create_fake_request(method, path))
390
+ else
391
+ RestClient::Response.create(body, net_http_resp, args)
392
+ end
393
+ end
394
+
395
+ def create_fake_request(method, path)
396
+ RestClient::Request.new(:method=>method, :url=>path)
397
+ end
351
398
  end
352
399
  end
@@ -1,5 +1,5 @@
1
1
  module ApipieBindings
2
2
  def self.version
3
- @version ||= Gem::Version.new '0.0.15'
3
+ @version ||= Gem::Version.new '0.0.16'
4
4
  end
5
5
  end
@@ -154,6 +154,49 @@ describe ApipieBindings::API do
154
154
  end
155
155
  end
156
156
 
157
+ context "redirects" do
158
+ def configure_api_with(options={})
159
+ default_options = {
160
+ :apidoc_cache_dir => 'test/unit/data',
161
+ :apidoc_cache_name => 'dummy'
162
+ }
163
+ ApipieBindings::API.new(default_options.merge(options))
164
+ end
165
+
166
+ it "should follow RestClient default behaviour by default" do
167
+ api = configure_api_with()
168
+ api.follow_redirects.must_equal :default
169
+ end
170
+
171
+ it "should be possible to change redirects handling" do
172
+ api = configure_api_with(:follow_redirects => :never)
173
+ api.follow_redirects.must_equal :never
174
+ end
175
+
176
+ it "should rise error on redirect when follow_redirects = :never" do
177
+ api = configure_api_with(:follow_redirects => :never)
178
+ block = api.send(:rest_client_call_block)
179
+ response = api.send(:create_fake_response, 301, "", "GET", "/", {})
180
+ proc { block.call(response) }.must_raise RestClient::MovedPermanently
181
+ end
182
+
183
+ it "should follow redirect when follow_redirects = :always" do
184
+ api = configure_api_with(:follow_redirects => :always)
185
+ block = api.send(:rest_client_call_block)
186
+ response = api.send(:create_fake_response, 301, "", "POST", "/", {})
187
+ response.expects(:follow_redirection)
188
+ block.call(response)
189
+ end
190
+
191
+ it "should use original handling when follow_redirects = :default" do
192
+ api = configure_api_with(:follow_redirects => :default)
193
+ block = api.send(:rest_client_call_block)
194
+ response = api.send(:create_fake_response, 301, "", "GET", "/", {})
195
+ response.expects(:return!)
196
+ block.call(response)
197
+ end
198
+ end
199
+
157
200
  context "credentials" do
158
201
 
159
202
  let(:fake_empty_response) {
@@ -203,6 +246,30 @@ describe ApipieBindings::API do
203
246
  api.check_cache
204
247
  end
205
248
  end
249
+
250
+ it "should clear credentials" do
251
+ Dir.mktmpdir do |dir|
252
+ credentials = ApipieBindings::AbstractCredentials.new
253
+ api = ApipieBindings::API.new({
254
+ :uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2,
255
+ :credentials => credentials})
256
+ credentials.expects(:clear)
257
+ api.clear_credentials
258
+ end
259
+ end
260
+
261
+ it "should call clear_credentials when doing authenticated call and auth error is raised" do
262
+ Dir.mktmpdir do |dir|
263
+ credentials = ApipieBindings::AbstractCredentials.new
264
+ api = ApipieBindings::API.new({:uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2,
265
+ :credentials => credentials})
266
+ api.expects(:clear_credentials)
267
+ api.stubs(:call_client).raises(RestClient::Unauthorized)
268
+ assert_raises RestClient::Unauthorized do
269
+ api.http_call(:get, '/path')
270
+ end
271
+ end
272
+ end
206
273
  end
207
274
 
208
275
  end
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apipie-bindings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Bačovský
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-21 00:00:00.000000000 Z
11
+ date: 2016-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.2.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.2.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rest-client
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.6.5
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
40
  version: 1.6.5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: oauth
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 10.1.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 10.1.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: thor
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
@@ -98,62 +98,62 @@ dependencies:
98
98
  name: minitest-spec-context
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - <
115
+ - - "<"
116
116
  - !ruby/object:Gem::Version
117
117
  version: 0.9.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - <
122
+ - - "<"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.9.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: mocha
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: ci_reporter
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: 1.6.3
146
- - - <
146
+ - - "<"
147
147
  - !ruby/object:Gem::Version
148
148
  version: 2.0.0
149
149
  type: :development
150
150
  prerelease: false
151
151
  version_requirements: !ruby/object:Gem::Requirement
152
152
  requirements:
153
- - - '>='
153
+ - - ">="
154
154
  - !ruby/object:Gem::Version
155
155
  version: 1.6.3
156
- - - <
156
+ - - "<"
157
157
  - !ruby/object:Gem::Version
158
158
  version: 2.0.0
159
159
  description: |
@@ -231,17 +231,17 @@ require_paths:
231
231
  - lib
232
232
  required_ruby_version: !ruby/object:Gem::Requirement
233
233
  requirements:
234
- - - '>='
234
+ - - ">="
235
235
  - !ruby/object:Gem::Version
236
236
  version: 1.8.7
237
237
  required_rubygems_version: !ruby/object:Gem::Requirement
238
238
  requirements:
239
- - - '>='
239
+ - - ">="
240
240
  - !ruby/object:Gem::Version
241
241
  version: '0'
242
242
  requirements: []
243
243
  rubyforge_project:
244
- rubygems_version: 2.4.4
244
+ rubygems_version: 2.4.8
245
245
  signing_key:
246
246
  specification_version: 4
247
247
  summary: The Ruby bindings for Apipie documented APIs
@@ -284,3 +284,4 @@ test_files:
284
284
  - test/unit/resource_test.rb
285
285
  - test/unit/route_test.rb
286
286
  - test/unit/test_helper.rb
287
+ has_rdoc: yard