minty 1.0.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/config +4 -0
  3. data/.devcontainer/Dockerfile +19 -0
  4. data/.devcontainer/devcontainer.json +37 -0
  5. data/.env.example +2 -0
  6. data/.gemrelease +2 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +33 -0
  8. data/.github/dependabot.yml +10 -0
  9. data/.github/stale.yml +20 -0
  10. data/.gitignore +18 -0
  11. data/.rspec +3 -0
  12. data/.rubocop.yml +9 -0
  13. data/CODE_OF_CONDUCT.md +3 -0
  14. data/DEPLOYMENT.md +61 -0
  15. data/DEVELOPMENT.md +35 -0
  16. data/Dockerfile +5 -0
  17. data/EXAMPLES.md +195 -0
  18. data/Gemfile +21 -0
  19. data/Gemfile.lock +250 -0
  20. data/Guardfile +39 -0
  21. data/LICENSE +21 -0
  22. data/Makefile +5 -0
  23. data/README.md +88 -0
  24. data/RUBYGEM.md +9 -0
  25. data/Rakefile +33 -0
  26. data/codecov.yml +22 -0
  27. data/lib/minty/algorithm.rb +7 -0
  28. data/lib/minty/api/authentication_endpoints.rb +30 -0
  29. data/lib/minty/api/v2.rb +8 -0
  30. data/lib/minty/client.rb +7 -0
  31. data/lib/minty/exception.rb +50 -0
  32. data/lib/minty/mixins/api_token_struct.rb +4 -0
  33. data/lib/minty/mixins/headers.rb +19 -0
  34. data/lib/minty/mixins/httpproxy.rb +125 -0
  35. data/lib/minty/mixins/initializer.rb +38 -0
  36. data/lib/minty/mixins/validation.rb +113 -0
  37. data/lib/minty/mixins.rb +23 -0
  38. data/lib/minty/version.rb +5 -0
  39. data/lib/minty.rb +11 -0
  40. data/lib/minty_client.rb +4 -0
  41. data/minty.gemspec +39 -0
  42. data/publish_rubygem.sh +10 -0
  43. data/spec/integration/lib/minty/api/api_authentication_spec.rb +122 -0
  44. data/spec/integration/lib/minty/minty_client_spec.rb +92 -0
  45. data/spec/lib/minty/client_spec.rb +223 -0
  46. data/spec/lib/minty/mixins/httpproxy_spec.rb +658 -0
  47. data/spec/lib/minty/mixins/initializer_spec.rb +121 -0
  48. data/spec/lib/minty/mixins/token_management_spec.rb +129 -0
  49. data/spec/lib/minty/mixins/validation_spec.rb +559 -0
  50. data/spec/spec_helper.rb +75 -0
  51. data/spec/support/credentials.rb +14 -0
  52. data/spec/support/dummy_class.rb +20 -0
  53. data/spec/support/dummy_class_for_proxy.rb +6 -0
  54. data/spec/support/dummy_class_for_restclient.rb +4 -0
  55. data/spec/support/dummy_class_for_tokens.rb +18 -0
  56. data/spec/support/import_users.json +13 -0
  57. data/spec/support/stub_response.rb +3 -0
  58. metadata +366 -0
@@ -0,0 +1,658 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'spec_helper'
5
+
6
+ describe Minty::Mixins::HTTPProxy do
7
+ before :each do
8
+ dummy_instance = DummyClassForProxy.new
9
+ dummy_instance.extend(Minty::Mixins::HTTPProxy)
10
+ dummy_instance.base_uri = 'https://minty.page'
11
+ dummy_instance.retry_count = 0
12
+
13
+ @instance = dummy_instance
14
+ @exception = DummyClassForRestClient.new
15
+ end
16
+
17
+ %i[get delete].each do |http_method|
18
+ context ".#{http_method}" do
19
+ it { expect(@instance).to respond_to(http_method.to_sym) }
20
+ it "should call send http #{http_method} method to path defined through HTTP" do
21
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
22
+ url: 'https://minty.page/test',
23
+ timeout: nil,
24
+ headers: { params: {} },
25
+ payload: nil)
26
+ .and_return(StubResponse.new({}, true, 200))
27
+ expect { @instance.send(http_method, '/test') }.not_to raise_error
28
+ end
29
+
30
+ it 'should not raise exception if data returned not in json format (should be fixed in v2)' do
31
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
32
+ url: 'https://minty.page/test',
33
+ timeout: nil,
34
+ headers: { params: {} },
35
+ payload: nil)
36
+ .and_return(StubResponse.new('Some random text here', true, 200))
37
+ expect { @instance.send(http_method, '/test') }.not_to raise_error
38
+ expect(@instance.send(http_method, '/test')).to eql('Some random text here')
39
+ end
40
+
41
+ it "should raise Minty::Unauthorized on send http #{http_method}
42
+ method to path defined through HTTP when 401 status received" do
43
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
44
+ url: 'https://minty.page/test',
45
+ timeout: nil,
46
+ headers: { params: {} },
47
+ payload: nil)
48
+ .and_return(StubResponse.new({}, false, 401))
49
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::Unauthorized)
50
+ end
51
+
52
+ it "should raise Minty::NotFound on send http #{http_method} method
53
+ to path defined through HTTP when 404 status received" do
54
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
55
+ url: 'https://minty.page/test',
56
+ timeout: nil,
57
+ headers: { params: {} },
58
+ payload: nil)
59
+ .and_return(StubResponse.new({}, false, 404))
60
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::NotFound)
61
+ end
62
+
63
+ it "should raise Minty::Unsupported on send http #{http_method} method
64
+ to path defined through HTTP when 418 or other unknown status received" do
65
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
66
+ url: 'https://minty.page/test',
67
+ timeout: nil,
68
+ headers: { params: {} },
69
+ payload: nil)
70
+ .and_return(StubResponse.new({}, false, 418))
71
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::Unsupported)
72
+ end
73
+
74
+ it "should raise Minty::RequestTimeout on send http #{http_method} method
75
+ to path defined through HTTP when RestClient::RequestTimeout received" do
76
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
77
+ url: 'https://minty.page/test',
78
+ timeout: nil,
79
+ headers: { params: {} },
80
+ payload: nil)
81
+ .and_raise(RestClient::Exceptions::OpenTimeout.new)
82
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::RequestTimeout)
83
+ end
84
+
85
+ it "should raise Minty::BadRequest on send http #{http_method} method
86
+ to path defined through HTTP when 400 status received" do
87
+ @exception.response = StubResponse.new({}, false, 400)
88
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
89
+ url: 'https://minty.page/test',
90
+ timeout: nil,
91
+ headers: { params: {} },
92
+ payload: nil)
93
+ .and_raise(@exception)
94
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::BadRequest)
95
+ end
96
+
97
+ it "should raise Minty::AccessDenied on send http #{http_method} method
98
+ to path defined through HTTP when 403" do
99
+ @exception.response = StubResponse.new({}, false, 403)
100
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
101
+ url: 'https://minty.page/test',
102
+ timeout: nil,
103
+ headers: { params: {} },
104
+ payload: nil)
105
+ .and_raise(@exception)
106
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::AccessDenied)
107
+ end
108
+
109
+ it "should raise Minty::RateLimitEncountered on send http #{http_method} method
110
+ to path defined through HTTP when 429 recieved" do
111
+ headers = {
112
+ x_ratelimit_limit: 10,
113
+ x_ratelimit_remaining: 0,
114
+ x_ratelimit_reset: 1_560_564_149
115
+ }
116
+ @exception.response = StubResponse.new({}, false, 429, headers)
117
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
118
+ url: 'https://minty.page/test',
119
+ timeout: nil,
120
+ headers: { params: {} },
121
+ payload: nil)
122
+ .and_raise(@exception)
123
+ expect { @instance.send(http_method, '/test') }.to raise_error { |error|
124
+ expect(error).to be_a(Minty::RateLimitEncountered)
125
+ expect(error).to have_attributes(
126
+ error_data: {
127
+ headers: headers,
128
+ code: 429
129
+ },
130
+ headers: headers,
131
+ http_code: 429,
132
+ reset: Time.zone.at(1_560_564_149)
133
+ )
134
+ }
135
+ end
136
+
137
+ it "should raise Minty::ServerError on send http #{http_method} method
138
+ to path defined through HTTP when 500 received" do
139
+ @exception.response = StubResponse.new({}, false, 500)
140
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
141
+ url: 'https://minty.page/test',
142
+ timeout: nil,
143
+ headers: { params: {} },
144
+ payload: nil)
145
+ .and_raise(@exception)
146
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::ServerError)
147
+ end
148
+
149
+ it 'should normalize path with Addressable::URI' do
150
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
151
+ url: 'https://minty.page/te%20st%23test',
152
+ timeout: nil,
153
+ headers: { params: {} },
154
+ payload: nil)
155
+ .and_return(StubResponse.new({}, true, 200))
156
+ expect { @instance.send(http_method, '/te st#test') }.not_to raise_error
157
+ end
158
+
159
+ context "when status 429 is recieved on send http #{http_method} method" do
160
+ it 'should retry 3 times when retry_count is not set' do
161
+ retry_instance = DummyClassForProxy.new
162
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
163
+ retry_instance.base_uri = 'https://minty.page'
164
+
165
+ @exception.response = StubResponse.new({}, false, 429)
166
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
167
+ url: 'https://minty.page/test',
168
+ timeout: nil,
169
+ headers: { params: {} },
170
+ payload: nil)
171
+ .and_raise(@exception)
172
+ expect(RestClient::Request).to receive(:execute).exactly(4).times
173
+
174
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
175
+ expect(error).to be_a(Minty::RateLimitEncountered)
176
+ }
177
+ end
178
+
179
+ it 'should retry 2 times when retry_count is set to 2' do
180
+ retry_instance = DummyClassForProxy.new
181
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
182
+ retry_instance.base_uri = 'https://minty.page'
183
+ retry_instance.retry_count = 2
184
+
185
+ @exception.response = StubResponse.new({}, false, 429)
186
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
187
+ url: 'https://minty.page/test',
188
+ timeout: nil,
189
+ headers: { params: {} },
190
+ payload: nil)
191
+ .and_raise(@exception)
192
+ expect(RestClient::Request).to receive(:execute).exactly(3).times
193
+
194
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
195
+ expect(error).to be_a(Minty::RateLimitEncountered)
196
+ }
197
+ end
198
+
199
+ it 'should not retry when retry_count is set to 0' do
200
+ retry_instance = DummyClassForProxy.new
201
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
202
+ retry_instance.base_uri = 'https://minty.page'
203
+ retry_instance.retry_count = 0
204
+
205
+ @exception.response = StubResponse.new({}, false, 429)
206
+
207
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
208
+ url: 'https://minty.page/test',
209
+ timeout: nil,
210
+ headers: { params: {} },
211
+ payload: nil)
212
+ .and_raise(@exception)
213
+
214
+ expect(RestClient::Request).to receive(:execute).exactly(1).times
215
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
216
+ expect(error).to be_a(Minty::RateLimitEncountered)
217
+ }
218
+ end
219
+
220
+ it 'should have have random retry times grow with jitter backoff' do
221
+ retry_instance = DummyClassForProxy.new
222
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
223
+ retry_instance.base_uri = 'https://minty.page'
224
+ retry_instance.retry_count = 2
225
+ time_entries = []
226
+ @time_start
227
+
228
+ @exception.response = StubResponse.new({}, false, 429)
229
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
230
+ url: 'https://minty.page/test',
231
+ timeout: nil,
232
+ headers: { params: {} },
233
+ payload: nil) do
234
+ time_entries.push(Time.now.to_f - @time_start.to_f)
235
+ @time_start = Time.now.to_f # restart the clock
236
+ raise @exception
237
+ end
238
+
239
+ @time_start = Time.now.to_f # start the clock
240
+ begin
241
+ retry_instance.send(http_method, '/test')
242
+ rescue StandardError
243
+ nil
244
+ end
245
+ time_entries_first_set = time_entries.shift(time_entries.length)
246
+
247
+ begin
248
+ retry_instance.send(http_method, '/test')
249
+ rescue StandardError
250
+ nil
251
+ end
252
+ time_entries.each_with_index do |entry, index|
253
+ expect(entry != time_entries_first_set[index]) if index > 0 # skip the first request
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ %i[post put patch].each do |http_method|
261
+ context ".#{http_method}" do
262
+ it { expect(@instance).to respond_to(http_method.to_sym) }
263
+ it "should call send http #{http_method} method to path defined through HTTP" do
264
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
265
+ url: 'https://minty.page/test',
266
+ timeout: nil,
267
+ headers: nil,
268
+ payload: '{}')
269
+ .and_return(StubResponse.new({}, true, 200))
270
+ expect { @instance.send(http_method, '/test') }.not_to raise_error
271
+ end
272
+
273
+ it 'should not raise exception if data returned not in json format (should be fixed in v2)' do
274
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
275
+ url: 'https://minty.page/test',
276
+ timeout: nil,
277
+ headers: nil,
278
+ payload: '{}')
279
+ .and_return(StubResponse.new('Some random text here', true, 200))
280
+ expect { @instance.send(http_method, '/test') }.not_to raise_error
281
+ expect(@instance.send(http_method, '/test')).to eql('Some random text here')
282
+ end
283
+
284
+ it "should raise Minty::Unauthorized on send http #{http_method} method
285
+ to path defined through HTTP when 401 status received" do
286
+ @exception.response = StubResponse.new({}, false, 401)
287
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
288
+ url: 'https://minty.page/test',
289
+ timeout: nil,
290
+ headers: nil,
291
+ payload: '{}')
292
+ .and_raise(@exception)
293
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::Unauthorized)
294
+ end
295
+
296
+ it "should raise Minty::RateLimitEncountered on send http #{http_method} method
297
+ to path defined through HTTP when 429 status received" do
298
+ headers = {
299
+ x_ratelimit_limit: 10,
300
+ x_ratelimit_remaining: 0,
301
+ x_ratelimit_reset: 1_560_564_149
302
+ }
303
+ @exception.response = StubResponse.new({}, false, 429, headers)
304
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
305
+ url: 'https://minty.page/test',
306
+ timeout: nil,
307
+ headers: nil,
308
+ payload: '{}')
309
+ .and_raise(@exception)
310
+ expect { @instance.send(http_method, '/test') }.to raise_error { |error|
311
+ expect(error).to be_a(Minty::RateLimitEncountered)
312
+ expect(error).to have_attributes(
313
+ error_data: {
314
+ headers: headers,
315
+ code: 429
316
+ },
317
+ headers: headers,
318
+ http_code: 429,
319
+ reset: Time.zone.at(1_560_564_149)
320
+ )
321
+ }
322
+ end
323
+
324
+ it "should raise Minty::NotFound on send http #{http_method} method
325
+ to path defined through HTTP when 404 status received" do
326
+ @exception.response = StubResponse.new({}, false, 404)
327
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
328
+ url: 'https://minty.page/test',
329
+ timeout: nil,
330
+ headers: nil,
331
+ payload: '{}')
332
+ .and_raise(@exception)
333
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::NotFound)
334
+ end
335
+
336
+ it "should raise Minty::Unsupported on send http #{http_method} method
337
+ to path defined through HTTP when 418 or other unknown status received" do
338
+ @exception.response = StubResponse.new({}, false, 418)
339
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
340
+ url: 'https://minty.page/test',
341
+ timeout: nil,
342
+ headers: nil,
343
+ payload: '{}')
344
+ .and_raise(@exception)
345
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::Unsupported)
346
+ end
347
+
348
+ it "should raise Minty::RequestTimeout on send http #{http_method} method
349
+ to path defined through HTTP when RestClient::RequestTimeout received" do
350
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
351
+ url: 'https://minty.page/test',
352
+ timeout: nil,
353
+ headers: nil,
354
+ payload: '{}')
355
+ .and_raise(RestClient::Exceptions::OpenTimeout.new)
356
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::RequestTimeout)
357
+ end
358
+
359
+ it "should raise Minty::BadRequest on send http #{http_method} method
360
+ to path defined through HTTP when 400 status received" do
361
+ @exception.response = StubResponse.new({}, false, 400)
362
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
363
+ url: 'https://minty.page/test',
364
+ timeout: nil,
365
+ headers: nil,
366
+ payload: '{}')
367
+ .and_raise(@exception)
368
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::BadRequest)
369
+ end
370
+
371
+ it "should raise Minty::ServerError on send http #{http_method} method
372
+ to path defined through HTTP when 500 received" do
373
+ @exception.response = StubResponse.new({}, false, 500)
374
+ allow(RestClient::Request).to receive(:execute).with(method: http_method, url: 'https://minty.page/test',
375
+ timeout: nil,
376
+ headers: nil,
377
+ payload: '{}')
378
+ .and_raise(@exception)
379
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::ServerError)
380
+ end
381
+
382
+ it 'should normalize path with Addressable::URI' do
383
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
384
+ url: 'https://minty.page/te%20st',
385
+ timeout: nil,
386
+ headers: nil,
387
+ payload: '{}')
388
+ .and_return(StubResponse.new({}, true, 200))
389
+ expect { @instance.send(http_method, '/te st') }.not_to raise_error
390
+ end
391
+
392
+ it 'should give the JSON representation of the error as the error message' do
393
+ res = JSON.generate('statusCode' => 404,
394
+ 'error' => 'Bad Request',
395
+ 'message' => "Path validation error: 'String does not match pattern ^.+\\|.+$:
396
+ 3241312' on property id (The user_id of the user to retrieve).",
397
+ 'errorCode' => 'invalid_uri')
398
+ expect(RestClient::Request).to receive(:execute).with(method: http_method,
399
+ url: 'https://minty.page/test',
400
+ timeout: nil,
401
+ headers: nil,
402
+ payload: '{}')
403
+ .and_return(StubResponse.new(res, true, 404))
404
+ expect { @instance.send(http_method, '/test') }.to raise_error(Minty::NotFound, res)
405
+ end
406
+
407
+ context "when status 429 is recieved on send http #{http_method} method" do
408
+ it 'should retry 3 times when retry_count is not set' do
409
+ retry_instance = DummyClassForProxy.new
410
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
411
+ retry_instance.base_uri = 'https://minty.page'
412
+
413
+ @exception.response = StubResponse.new({}, false, 429)
414
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
415
+ url: 'https://minty.page/test',
416
+ timeout: nil,
417
+ headers: nil,
418
+ payload: '{}')
419
+ .and_raise(@exception)
420
+ expect(RestClient::Request).to receive(:execute).exactly(4).times
421
+
422
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
423
+ expect(error).to be_a(Minty::RateLimitEncountered)
424
+ }
425
+ end
426
+
427
+ it 'should retry 2 times when retry_count is set to 2' do
428
+ retry_instance = DummyClassForProxy.new
429
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
430
+ retry_instance.base_uri = 'https://minty.page'
431
+ retry_instance.retry_count = 2
432
+
433
+ @exception.response = StubResponse.new({}, false, 429)
434
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
435
+ url: 'https://minty.page/test',
436
+ timeout: nil,
437
+ headers: nil,
438
+ payload: '{}')
439
+ .and_raise(@exception)
440
+ expect(RestClient::Request).to receive(:execute).exactly(3).times
441
+
442
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
443
+ expect(error).to be_a(Minty::RateLimitEncountered)
444
+ }
445
+ end
446
+
447
+ it 'should not retry when retry_count is set to 0' do
448
+ retry_instance = DummyClassForProxy.new
449
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
450
+ retry_instance.base_uri = 'https://minty.page'
451
+ retry_instance.retry_count = 0
452
+
453
+ @exception.response = StubResponse.new({}, false, 429)
454
+
455
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
456
+ url: 'https://minty.page/test',
457
+ timeout: nil,
458
+ headers: nil,
459
+ payload: '{}')
460
+ .and_raise(@exception)
461
+
462
+ expect(RestClient::Request).to receive(:execute).exactly(1).times
463
+ expect { retry_instance.send(http_method, '/test') }.to raise_error { |error|
464
+ expect(error).to be_a(Minty::RateLimitEncountered)
465
+ }
466
+ end
467
+
468
+ it 'should have have random retry times grow with jitter backoff' do
469
+ retry_instance = DummyClassForProxy.new
470
+ retry_instance.extend(Minty::Mixins::HTTPProxy)
471
+ retry_instance.base_uri = 'https://minty.page'
472
+ retry_instance.retry_count = 2
473
+ time_entries = []
474
+ @time_start
475
+
476
+ @exception.response = StubResponse.new({}, false, 429)
477
+ allow(RestClient::Request).to receive(:execute).with(method: http_method,
478
+ url: 'https://minty.page/test',
479
+ timeout: nil,
480
+ headers: nil,
481
+ payload: '{}') do
482
+ time_entries.push(Time.now.to_f - @time_start.to_f)
483
+ @time_start = Time.now.to_f # restart the clock
484
+ raise @exception
485
+ end
486
+
487
+ @time_start = Time.now.to_f # start the clock
488
+ begin
489
+ retry_instance.send(http_method, '/test')
490
+ rescue StandardError
491
+ nil
492
+ end
493
+ time_entries_first_set = time_entries.shift(time_entries.length)
494
+
495
+ begin
496
+ retry_instance.send(http_method, '/test')
497
+ rescue StandardError
498
+ nil
499
+ end
500
+ time_entries.each_with_index do |entry, index|
501
+ expect(entry != time_entries_first_set[index]) if index > 0 # skip the first request
502
+ end
503
+ end
504
+ end
505
+ end
506
+ end
507
+
508
+ context 'Renewing tokens' do
509
+ let(:httpproxy_instance) do
510
+ DummyClassForTokens.new(
511
+ client_id: 'test-client-id',
512
+ client_secret: 'test-client-secret',
513
+ domain: 'minty.page'
514
+ )
515
+ end
516
+
517
+ %i[get delete].each do |http_method|
518
+ context "for #{http_method}" do
519
+ it 'should renew the token' do
520
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
521
+ method: :post,
522
+ url: 'https://minty.page/oauth/token'
523
+ )).and_return(StubResponse.new({
524
+ 'access_token' => 'access_token',
525
+ 'expires_in' => 86_400
526
+ },
527
+ true,
528
+ 200))
529
+
530
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
531
+ method: http_method,
532
+ url: 'https://minty.page/test'
533
+ )).and_return(StubResponse.new('Some random text here',
534
+ true, 200))
535
+
536
+ expect { httpproxy_instance.send(http_method, '/test') }.not_to raise_error
537
+ end
538
+ end
539
+ end
540
+
541
+ %i[post put patch].each do |http_method|
542
+ context "for #{http_method}" do
543
+ it 'should renew the token' do
544
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
545
+ method: :post,
546
+ url: 'https://minty.page/oauth/token'
547
+ )).and_return(StubResponse.new({
548
+ 'access_token' => 'access_token',
549
+ 'expires_in' => 86_400
550
+ },
551
+ true,
552
+ 200))
553
+
554
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
555
+ method: http_method,
556
+ url: 'https://minty.page/test',
557
+ headers: hash_including('Authorization' => 'Bearer access_token')
558
+ )).and_return(StubResponse.new('Some random text here',
559
+ true, 200))
560
+
561
+ expect { httpproxy_instance.send(http_method, '/test') }.not_to raise_error
562
+ end
563
+ end
564
+ end
565
+ end
566
+
567
+ context 'Using cached tokens' do
568
+ let(:httpproxy_instance) do
569
+ DummyClassForTokens.new(
570
+ client_id: 'test-client-id',
571
+ client_secret: 'test-client-secret',
572
+ domain: 'minty.page',
573
+ token: 'access_token',
574
+ token_expires_at: Time.now.to_i + 86_400
575
+ )
576
+ end
577
+
578
+ %i[get delete].each do |http_method|
579
+ context "for #{http_method}" do
580
+ it 'should use the cached token' do
581
+ expect(RestClient::Request).not_to receive(:execute).with(hash_including(
582
+ method: :post,
583
+ url: 'https://minty.page/oauth/token'
584
+ ))
585
+
586
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
587
+ method: http_method,
588
+ url: 'https://minty.page/test',
589
+ headers: hash_including(params: {},
590
+ 'Authorization' => 'Bearer access_token')
591
+ )).and_return(StubResponse.new('Some random text here',
592
+ true, 200))
593
+
594
+ expect { httpproxy_instance.send(http_method, '/test') }.not_to raise_error
595
+ end
596
+ end
597
+ end
598
+
599
+ %i[post put patch].each do |http_method|
600
+ context "for #{http_method}" do
601
+ it 'should use the cached token' do
602
+ expect(RestClient::Request).not_to receive(:execute).with(hash_including(
603
+ method: :post,
604
+ url: 'https://minty.page/oauth/token'
605
+ ))
606
+
607
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
608
+ method: http_method,
609
+ url: 'https://minty.page/test',
610
+ headers: hash_including('Authorization' => 'Bearer access_token')
611
+ )).and_return(StubResponse.new('Some random text here',
612
+ true, 200))
613
+
614
+ expect { httpproxy_instance.send(http_method, '/test') }.not_to raise_error
615
+ end
616
+ end
617
+ end
618
+ end
619
+
620
+ context 'Normal operation' do
621
+ let(:httpproxy_instance) do
622
+ DummyClassForTokens.new(
623
+ client_id: 'test-client-id',
624
+ client_secret: 'test-client-secret',
625
+ domain: 'minty.page',
626
+ token: 'access_token',
627
+ token_expires_at: Time.now.to_i + 86_400
628
+ )
629
+ end
630
+
631
+ # This sets up a test matrix to verify that both :get and :delete calls (the only two HTTP methods in the proxy that mutated headers)
632
+ # don't bleed query params into subsequent calls to :post :patch and :put.
633
+ %i[get delete].each do |http_get_delete|
634
+ %i[post patch put].each do |http_ppp|
635
+ it "should not bleed :#{http_get_delete} headers/parameters to the subsequent :#{http_ppp} request" do
636
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
637
+ method: http_get_delete,
638
+ url: "https://minty.page/test-#{http_get_delete}",
639
+ headers: hash_including(params: { email: 'test@test.com' })
640
+ )).and_return(StubResponse.new('OK', true, 200))
641
+
642
+ # email: parameter that is sent in the GET request should not appear
643
+ # as a parameter in the `headers` hash for the subsequent PATCH request.
644
+ expect(RestClient::Request).to receive(:execute).with(hash_including(
645
+ method: http_ppp,
646
+ url: "https://minty.page/test-#{http_ppp}",
647
+ headers: hash_not_including(:params)
648
+ )).and_return(StubResponse.new('OK', true, 200))
649
+
650
+ expect do
651
+ httpproxy_instance.send(http_get_delete, "/test-#{http_get_delete}", { email: 'test@test.com' })
652
+ end.not_to raise_error
653
+ expect { httpproxy_instance.send(http_ppp, "/test-#{http_ppp}") }.not_to raise_error
654
+ end
655
+ end
656
+ end
657
+ end
658
+ end