apipie-bindings 0.0.15 → 0.0.16

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: 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