rest-client-wrapper 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module RestClientWrapper
20
+
21
+ VERSION = "3.0.1".freeze
22
+
23
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ lib = File.expand_path("lib", __dir__)
20
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
21
+ require "rest_client_wrapper/version"
22
+
23
+ Gem::Specification.new do |s|
24
+ s.name = "rest-client-wrapper"
25
+ s.version = RestClientWrapper::VERSION
26
+ s.platform = Gem::Platform::RUBY
27
+ s.authors = ["University of Adelaide"]
28
+ s.email = ["myuni.admin@adelaide.edu.au"]
29
+ s.homepage = "https://github.com/universityofadelaide/rest-client-wrapper"
30
+ s.summary = "Rest client wrapper"
31
+ s.description = "Generic REST client wrapper"
32
+ s.license = "GPL 3.0"
33
+ s.required_ruby_version = ">= 2.4.0"
34
+
35
+ s.add_runtime_dependency "json", "~> 1.8", ">= 1.8.3"
36
+ s.add_runtime_dependency "oauth2", "~> 1.2"
37
+ s.add_runtime_dependency "rack", "~> 2.0.5"
38
+ s.add_runtime_dependency "rest-client", "~> 2.0.2"
39
+ s.add_runtime_dependency "typhoeus", "~> 1.0", ">= 1.0.1"
40
+
41
+ s.add_development_dependency "colorize", "~> 0.7", ">= 0.7.0"
42
+ s.add_development_dependency "geminabox", "~> 0.13.0"
43
+ s.add_development_dependency "rspec", "~> 3.4", ">= 3.4.0"
44
+
45
+ s.metadata["allowed_push_host"] = "https://rubygems.org"
46
+
47
+ s.files = Dir.glob("lib/**/*.{rake,rb}") + ["#{ s.name }.gemspec", "README.md"]
48
+ s.test_files = `find spec/*`.split("\n")
49
+ s.executables = []
50
+ s.require_paths = ["lib"]
51
+ end
@@ -0,0 +1,103 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ # Authenticator::Oauth Specs
22
+ module RestClientWrapper
23
+
24
+ describe Authenticator::Oauth do
25
+
26
+ before(:context) do
27
+ @client_id = "client_id"
28
+ @client_secret = "client_secret"
29
+ @api_token_uri = URI.parse("http://fake_oauth_token.com/token_url_path")
30
+ end
31
+
32
+ describe "::get_access_token" do
33
+
34
+ before(:example) do
35
+ WebMock.reset_executed_requests!
36
+ @oauth = Authenticator::Oauth.new(
37
+ {
38
+ site: "#{ @api_token_uri.scheme }://#{ @api_token_uri.host }",
39
+ token_url_path: @api_token_uri.path,
40
+ client_id: @client_id,
41
+ client_secret: @client_secret
42
+ }
43
+ )
44
+ @current_token = FactoryBot.build(:token).token
45
+ request = FactoryBot.build(:oauth_token_request, { headers: FactoryBot.build(:request_headers, { host: @api_token_uri.host }).to_h }).to_h
46
+ response = FactoryBot.build(:auth_token_response).to_h
47
+ @response_body = response[:body]
48
+ response[:body] = lambda { |_request|
49
+ sleep 1 # Simulate network latency.
50
+ @response_body
51
+ }
52
+ @authenticate_request = stub_request(:post, @api_token_uri.to_s).with(request).to_return(response)
53
+ end
54
+
55
+ context "when multiple threads are trying to authenticate" do
56
+
57
+ it "will only make one API request to renew the access token" do
58
+ t1 = Thread.new do
59
+ Authenticator::Oauth.authenticate({ client_id: @client_id })
60
+ end
61
+
62
+ sleep(1) # Give t1 a head start so that it can get the lock before t2 does
63
+ t2 = Thread.new do
64
+ Authenticator::Oauth.authenticate({ client_id: @client_id, access_token: @current_token })
65
+ end
66
+
67
+ t1.join
68
+ t2.join
69
+
70
+ parsed_response = JSON.parse(@response_body).symbolize_keys
71
+
72
+ expect(@oauth.tokens[@client_id][:access_token]).to eq(parsed_response[:access_token])
73
+ # Only expect one request as thread 1 (t1) has already got a new token thread 2 (t2) will use the new token.
74
+ expect(@authenticate_request).to have_been_requested.times(1)
75
+ end
76
+
77
+ end
78
+
79
+ context "when token is expired" do
80
+
81
+ before(:example) do
82
+ WebMock.reset_executed_requests!
83
+ @expired_token = FactoryBot.build(:token).token
84
+ @request = FactoryBot.build(:oauth_token_request, { headers: FactoryBot.build(:request_headers, { host: @api_token_uri.host }).to_h }).to_h
85
+ @response = FactoryBot.build(:auth_token_response).to_h
86
+ @authenticate_request = stub_request(:post, @api_token_uri.to_s).with(@request).to_return(@response)
87
+ end
88
+
89
+ it "will make an API call to get a new token" do
90
+ Authenticator::Oauth.authenticate({ client_id: @client_id, access_token: @expired_token })
91
+ parsed_response = JSON.parse(@response[:body]).symbolize_keys
92
+
93
+ expect(@oauth.tokens[@client_id][:access_token]).to eq(parsed_response[:access_token])
94
+ expect(@authenticate_request).to have_been_requested.times(1)
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,48 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ FactoryBot.define do
20
+ factory :request, { class: OpenStruct } do |f|
21
+ skip_create
22
+ f.body { FactoryBot.build(:request_body).to_h }
23
+ f.headers { FactoryBot.build(:request_headers).to_h }
24
+ end
25
+
26
+ factory :oauth_token_request, { class: OpenStruct } do |f|
27
+ skip_create
28
+ f.body { FactoryBot.build(:oauth_request_body).to_h }
29
+ f.headers { FactoryBot.build(:request_headers).to_h }
30
+ end
31
+
32
+ factory :oauth_request_body, { class: OpenStruct } do |f|
33
+ skip_create
34
+ f.client_id { "client_id" }
35
+ f.client_secret { "client_secret" }
36
+ f.grant_type { "client_credentials" }
37
+ end
38
+
39
+ factory :request_body, { class: OpenStruct } do |f|
40
+ skip_create
41
+ f.course_id { Faker::Hipster.sentence(5) }
42
+ end
43
+
44
+ factory :request_headers, { class: OpenStruct } do |f|
45
+ skip_create
46
+ f.host { "fake_oauth_token.com" }
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ FactoryBot.define do
20
+ factory :auth_token_response, { class: OpenStruct } do |f|
21
+ skip_create
22
+ f.status { 200 }
23
+ f.body { "{\"token_type\":\"Bearer\",\"access_token\":\"#{ FactoryBot.build(:token).token }\",\"expires_in\":3600,\"refresh_token\":\"#{ FactoryBot.build(:token).token }\"}" }
24
+ f.headers { { content_type: "application/json; charset=utf-8" } }
25
+ end
26
+
27
+ factory :response, { class: OpenStruct } do |f|
28
+ skip_create
29
+ f.status { 200 }
30
+ f.body { "{\"result\":\"success\"}" }
31
+ f.headers { { content_type: "application/json; charset=utf-8" } }
32
+ end
33
+
34
+ factory :paginated_response, { class: OpenStruct } do |_f|
35
+ status { 200 }
36
+ body { "{\"result\":\"success\"}" }
37
+ headers do
38
+ { content_type: "application/json; charset=utf-8",
39
+ link: "" }
40
+ end
41
+ end
42
+
43
+ factory :token, { class: OpenStruct } do |f|
44
+ skip_create
45
+ f.token { Faker::Crypto.sha1 }
46
+ end
47
+ end
@@ -0,0 +1,185 @@
1
+ # Copyright (C) 2019 The University of Adelaide
2
+ #
3
+ # This file is part of Rest-Client-Wrapper.
4
+ #
5
+ # Rest-Client-Wrapper is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Rest-Client-Wrapper is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Rest-Client-Wrapper. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ # Request Specs
22
+ module RestClientWrapper # rubocop:disable Metrics/ModuleLength
23
+
24
+ describe Request do
25
+ before(:context) do
26
+ @api_uri = URI.parse("http://fake_site.com")
27
+ @param_hash = { key: "value" }
28
+ @non_hash_value = 1
29
+ end
30
+
31
+ describe "#http_method" do
32
+
33
+ before(:example) do
34
+ @non_http_method = :test
35
+ @non_symbol_value = 1
36
+ end
37
+
38
+ context "when http_method is not a valid http method" do
39
+
40
+ it "will raise TypeError" do
41
+ expect { Request.new({ http_method: @non_http_method, uri: @api_uri }) }.to raise_error(ArgumentError)
42
+ end
43
+
44
+ end
45
+
46
+ context "when http_method is not a symbol" do
47
+
48
+ it "will raise TypeError" do
49
+ expect { Request.new({ http_method: @non_symbol_value, uri: @api_uri }) }.to raise_error(TypeError)
50
+ end
51
+
52
+ end
53
+
54
+ context "when http method :get is assigned" do
55
+
56
+ it "value is assigned to request http_method" do
57
+ request = Request.new({ http_method: :get, uri: @api_uri })
58
+ expect(request.http_method).to eq(:get)
59
+ end
60
+
61
+ end
62
+
63
+ context "when http method :post is assigned" do
64
+
65
+ it "value is assigned to request http_method" do
66
+ request = Request.new({ http_method: :post, uri: @api_uri })
67
+ expect(request.http_method).to eq(:post)
68
+ end
69
+
70
+ end
71
+
72
+ context "when http method :put is assigned" do
73
+
74
+ it "value is assigned to request http_method" do
75
+ request = Request.new({ http_method: :put, uri: @api_uri })
76
+ expect(request.http_method).to eq(:put)
77
+ end
78
+
79
+ end
80
+
81
+ context "when http method :delete is assigned" do
82
+
83
+ it "value is assigned to request http_method" do
84
+ request = Request.new({ http_method: :delete, uri: @api_uri })
85
+ expect(request.http_method).to eq(:delete)
86
+ end
87
+
88
+ end
89
+
90
+ context "when http method :connect is assigned" do
91
+
92
+ it "value is assigned to request http_method" do
93
+ request = Request.new({ http_method: :connect, uri: @api_uri })
94
+ expect(request.http_method).to eq(:connect)
95
+ end
96
+
97
+ end
98
+
99
+ context "when http method :options is assigned" do
100
+
101
+ it "value is assigned to request http_method" do
102
+ request = Request.new({ http_method: :options, uri: @api_uri })
103
+ expect(request.http_method).to eq(:options)
104
+ end
105
+
106
+ end
107
+
108
+ context "when http method :trace is assigned" do
109
+
110
+ it "value is assigned to request http_method" do
111
+ request = Request.new({ http_method: :trace, uri: @api_uri })
112
+ expect(request.http_method).to eq(:trace)
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ describe "#segment_params" do
120
+
121
+ context "when segment_params is not a hash" do
122
+
123
+ it "will raise TypeError" do
124
+ expect { Request.new({ http_method: :get, uri: @api_uri, segment_params: @non_hash_value }) }.to raise_error(TypeError)
125
+ end
126
+
127
+ end
128
+
129
+ context "when segment_params is a hash" do
130
+
131
+ it "value is assigned to request segment_params" do
132
+ request = Request.new({ http_method: :get, uri: @api_uri, segment_params: @param_hash })
133
+ expect(request.segment_params).to eq(@param_hash)
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ describe "#payload" do
141
+
142
+ context "when payload is not a hash" do
143
+
144
+ it "will raise TypeError" do
145
+ expect { Request.new({ http_method: :get, uri: @api_uri, segment_params: @param_hash, payload: @non_hash_value }) }.to raise_error(TypeError)
146
+ end
147
+
148
+ end
149
+
150
+ context "when payload is a hash" do
151
+
152
+ it "value is assigned to request payload" do
153
+ request = Request.new({ http_method: :get, uri: @api_uri, segment_params: @param_hash, payload: @param_hash })
154
+ expect(request.payload).to eq(@param_hash)
155
+ end
156
+
157
+ end
158
+
159
+ end
160
+
161
+ describe "#headers" do
162
+
163
+ context "when headers is not a hash" do
164
+
165
+ it "will raise TypeError" do
166
+ request = Request.new({ http_method: :get, uri: @api_uri, segment_params: @param_hash, payload: @param_hash })
167
+ expect { request.headers = @non_hash_value }.to raise_error(TypeError)
168
+ end
169
+
170
+ end
171
+
172
+ context "when headers is a hash" do
173
+
174
+ it "value is assigned to request header" do
175
+ request = Request.new({ http_method: :get, uri: @api_uri, segment_params: @param_hash, payload: @param_hash })
176
+ expect(request.payload).to eq(@param_hash)
177
+ end
178
+
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+
185
+ end