finapps_core 5.0.7 → 5.0.13
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 +4 -4
- data/.github/release-drafter.yml +49 -0
- data/.github/workflows/main.yaml +37 -0
- data/.github/workflows/release-drafter.yml +15 -0
- data/.github/workflows/release.yml +54 -0
- data/.github/workflows/verify-pr-labeled.yml +14 -0
- data/.rubocop.yml +123 -73
- data/.ruby-version +1 -1
- data/.tmuxinator.yml +20 -0
- data/.travis.yml +5 -6
- data/finapps_core.gemspec +11 -11
- data/lib/finapps_core.rb +1 -0
- data/lib/finapps_core/middleware/middleware.rb +6 -3
- data/lib/finapps_core/middleware/request/accept_json.rb +2 -1
- data/lib/finapps_core/middleware/request/x_tenant_id.rb +20 -0
- data/lib/finapps_core/middleware/response/raise_error.rb +36 -7
- data/lib/finapps_core/rest/base_client.rb +20 -32
- data/lib/finapps_core/rest/configuration.rb +18 -5
- data/lib/finapps_core/rest/connection.rb +32 -22
- data/lib/finapps_core/rest/defaults.rb +1 -1
- data/lib/finapps_core/utils/loggeable.rb +1 -1
- data/lib/finapps_core/utils/validatable.rb +1 -1
- data/lib/finapps_core/version.rb +1 -1
- data/spec/core_extensions/object/is_integer_spec.rb +6 -7
- data/spec/middleware/request/accept_json_spec.rb +7 -3
- data/spec/middleware/request/no_encoding_basic_authentication_spec.rb +15 -6
- data/spec/middleware/request/request_id_spec.rb +4 -4
- data/spec/middleware/request/tenant_authentication_spec.rb +21 -14
- data/spec/middleware/request/user_agent_spec.rb +8 -3
- data/spec/middleware/request/x_consumer_id_spec.rb +4 -4
- data/spec/middleware/request/x_tenant_id_spec.rb +16 -0
- data/spec/middleware/response/raise_error_spec.rb +47 -15
- data/spec/rest/base_client_spec.rb +87 -43
- data/spec/rest/configuration_spec.rb +25 -18
- data/spec/rest/credentials_spec.rb +4 -4
- data/spec/rest/defaults_spec.rb +1 -1
- data/spec/rest/resources_spec.rb +10 -20
- data/spec/spec_helper.rb +3 -3
- data/spec/support/fake_api.rb +1 -1
- data/spec/utils/validatable_spec.rb +9 -8
- metadata +78 -69
@@ -7,22 +7,31 @@ RSpec.describe FinAppsCore::Middleware::NoEncodingBasicAuthentication do
|
|
7
7
|
app = proc {|env| env }
|
8
8
|
|
9
9
|
context 'when credentials were provided' do
|
10
|
-
let(:middleware) {
|
10
|
+
let(:middleware) { described_class.new(app, :token) }
|
11
11
|
let(:expected_header_value) { 'Bearer token' }
|
12
12
|
|
13
13
|
context 'when header was not previously set' do
|
14
|
-
let(:request_env) { { request_headers: {} } }
|
15
14
|
subject(:result) { middleware.call(request_env) }
|
16
15
|
|
17
|
-
|
16
|
+
let(:request_env) { {request_headers: {}} }
|
17
|
+
|
18
|
+
it('generates a header') {
|
19
|
+
expect(result[:request_headers][key]).to eq(expected_header_value)
|
20
|
+
}
|
18
21
|
end
|
19
22
|
|
20
23
|
context 'when header was previously set' do
|
21
|
-
let(:request_env) { { request_headers: { key => 'foo' } } }
|
22
24
|
subject(:result) { middleware.call(request_env) }
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
+
let(:request_env) { {request_headers: {key => 'foo'}} }
|
27
|
+
|
28
|
+
it('does not override existing header') {
|
29
|
+
expect(result[:request_headers][key]).to eq('foo')
|
30
|
+
}
|
31
|
+
|
32
|
+
it('does not generate a header') {
|
33
|
+
expect(result[:request_headers][key]).not_to eq(expected_header_value)
|
34
|
+
}
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::RequestId do
|
4
|
-
let(:key) { FinAppsCore::Middleware::RequestId::KEY }
|
5
4
|
let(:id) { 'request_id' }
|
6
5
|
let(:fake_app) { proc {|env| env } }
|
7
|
-
let(:env) { {
|
6
|
+
let(:env) { {request_headers: {}} }
|
8
7
|
|
9
8
|
describe '#call' do
|
10
|
-
subject {
|
9
|
+
subject(:request_id) { described_class.new(fake_app, id) }
|
11
10
|
|
12
11
|
it('generates a X-Request-Id header') do
|
13
|
-
|
12
|
+
key = FinAppsCore::Middleware::RequestId::KEY
|
13
|
+
expect(request_id.call(env)[:request_headers][key]).to eq(id)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::TenantAuthentication do
|
4
|
-
let(:valid_tenant_options) { VALID_CREDENTIALS }
|
5
|
-
let(:key) { FinAppsCore::Middleware::TenantAuthentication::KEY }
|
6
|
-
|
7
4
|
describe '#call' do
|
8
|
-
|
5
|
+
subject(:actual_header) do
|
6
|
+
middleware.call(request_env)[:request_headers][key]
|
7
|
+
end
|
9
8
|
|
10
9
|
context 'when company credentials were provided' do
|
11
|
-
let(:
|
12
|
-
let(:
|
10
|
+
let(:key) { FinAppsCore::Middleware::TenantAuthentication::KEY }
|
11
|
+
let(:middleware) do
|
12
|
+
fake_app = proc {|env| env }
|
13
|
+
described_class.new(fake_app, VALID_CREDENTIALS[:token])
|
14
|
+
end
|
15
|
+
let(:expected_header) { VALID_CREDENTIALS[:token] }
|
13
16
|
|
14
17
|
context 'when header was not previously set' do
|
15
|
-
let(:request_env) { {
|
16
|
-
subject(:actual_header) { middleware.call(request_env)[:request_headers][key] }
|
18
|
+
let(:request_env) { {request_headers: {}} }
|
17
19
|
|
18
|
-
it('generates a Tenant Authentication header') {
|
20
|
+
it('generates a Tenant Authentication header') {
|
21
|
+
expect(actual_header).to eq(expected_header)
|
22
|
+
}
|
19
23
|
end
|
20
24
|
|
21
25
|
context 'when header was previously set' do
|
22
|
-
let(:
|
23
|
-
|
24
|
-
|
26
|
+
let(:request_env) { {request_headers: {key => 'foo'}} }
|
27
|
+
|
28
|
+
it('does not override existing Tenant Authentication header') {
|
29
|
+
expect(actual_header).to eq('foo')
|
30
|
+
}
|
25
31
|
|
26
|
-
it('does not
|
27
|
-
|
32
|
+
it('does not generate a Tenant Authentication header') {
|
33
|
+
expect(actual_header).not_to eq(expected_header)
|
34
|
+
}
|
28
35
|
end
|
29
36
|
end
|
30
37
|
end
|
@@ -2,12 +2,17 @@
|
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::UserAgent do
|
4
4
|
let(:fake_app) { proc {|env| env } }
|
5
|
+
|
5
6
|
describe '#call' do
|
6
|
-
subject {
|
7
|
-
|
7
|
+
subject(:user_agent) { described_class.new(fake_app) }
|
8
|
+
|
9
|
+
let(:key) { FinAppsCore::Middleware::UserAgent::KEY }
|
10
|
+
|
11
|
+
env = {request_headers: {}}
|
8
12
|
|
9
13
|
it('generates a UserAgent header') do
|
10
|
-
expect(
|
14
|
+
expect(user_agent.call(env)[:request_headers][key])
|
15
|
+
.to start_with('finapps-ruby')
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::XConsumerId do
|
4
|
-
let(:key) { FinAppsCore::Middleware::XConsumerId::KEY }
|
5
4
|
let(:id) { 'valid_consumer_id' }
|
6
5
|
let(:fake_app) { proc {|env| env } }
|
7
|
-
let(:env) { {
|
6
|
+
let(:env) { {request_headers: {}} }
|
8
7
|
|
9
8
|
describe '#call' do
|
10
|
-
subject {
|
9
|
+
subject(:x_consumer_id) { described_class.new(fake_app, id) }
|
11
10
|
|
12
11
|
it('generates an X-Consumer-ID header') do
|
13
|
-
|
12
|
+
key = FinAppsCore::Middleware::XConsumerId::KEY
|
13
|
+
expect(x_consumer_id.call(env)[:request_headers][key]).to eq(id)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe FinAppsCore::Middleware::XTenantId do
|
4
|
+
let(:id) { 'valid_tenant_id' }
|
5
|
+
let(:fake_app) { proc {|env| env } }
|
6
|
+
let(:env) { {request_headers: {}} }
|
7
|
+
|
8
|
+
describe '#call' do
|
9
|
+
subject(:x_tenant_id) { described_class.new(fake_app, id) }
|
10
|
+
|
11
|
+
it('generates an X-Tenant-ID header') do
|
12
|
+
key = FinAppsCore::Middleware::XTenantId::KEY
|
13
|
+
expect(x_tenant_id.call(env)[:request_headers][key]).to eq(id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -2,39 +2,71 @@
|
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::Middleware::RaiseError do
|
4
4
|
let(:fake_app) { proc {|env| env } }
|
5
|
-
|
5
|
+
|
6
|
+
before do
|
7
|
+
stub_const('Env', Struct.new(:status, :response_headers, :body))
|
8
|
+
end
|
6
9
|
|
7
10
|
describe '#on_complete' do
|
8
|
-
subject {
|
11
|
+
subject(:error_raiser) { described_class.new(fake_app) }
|
9
12
|
|
10
|
-
context '
|
13
|
+
context 'with successful requests' do
|
11
14
|
let(:env) { Env.new(200) }
|
12
|
-
|
15
|
+
|
16
|
+
it { expect { error_raiser.on_complete(env) }.not_to raise_error }
|
13
17
|
end
|
14
|
-
|
15
|
-
|
18
|
+
|
19
|
+
context 'with invalid session errors' do
|
20
|
+
let(:env) do
|
21
|
+
body = '{"messages":["Invalid User Identifier or Credentials"]}'
|
22
|
+
Env.new(401, {}, body)
|
23
|
+
end
|
24
|
+
|
16
25
|
error_message = 'API Invalid Session'
|
17
|
-
it {
|
26
|
+
it {
|
27
|
+
expect { error_raiser.on_complete(env) }
|
28
|
+
.to raise_error(FinAppsCore::ApiUnauthenticatedError, error_message)
|
29
|
+
}
|
18
30
|
end
|
19
|
-
|
31
|
+
|
32
|
+
context 'with client errors' do
|
20
33
|
let(:env) { Env.new(404, {}, '{"messages":["Resource Not Found"]}') }
|
34
|
+
|
21
35
|
error_message = 'the server responded with status 404'
|
22
|
-
it {
|
36
|
+
it {
|
37
|
+
expect { error_raiser.on_complete(env) }
|
38
|
+
.to raise_error(Faraday::ClientError, error_message)
|
39
|
+
}
|
23
40
|
end
|
24
|
-
|
41
|
+
|
42
|
+
context 'with connection failed error' do
|
25
43
|
let(:env) { Env.new(407) }
|
44
|
+
|
26
45
|
error_message = 'Connection Failed'
|
27
|
-
it {
|
46
|
+
it {
|
47
|
+
expect { error_raiser.on_complete(env) }
|
48
|
+
.to raise_error(FinAppsCore::ConnectionFailedError, error_message)
|
49
|
+
}
|
28
50
|
end
|
29
|
-
|
51
|
+
|
52
|
+
context 'with session timeout error' do
|
30
53
|
let(:env) { Env.new(419) }
|
54
|
+
|
31
55
|
error_message = 'API Session Timed out'
|
32
|
-
it {
|
56
|
+
it {
|
57
|
+
expect { error_raiser.on_complete(env) }
|
58
|
+
.to raise_error(FinAppsCore::ApiSessionTimeoutError, error_message)
|
59
|
+
}
|
33
60
|
end
|
34
|
-
|
61
|
+
|
62
|
+
context 'with user lockout error' do
|
35
63
|
let(:env) { Env.new(403, {}, '{"messages":["Account is locked"]}') }
|
64
|
+
|
36
65
|
error_message = 'User is Locked'
|
37
|
-
it {
|
66
|
+
it {
|
67
|
+
expect { error_raiser.on_complete(env) }
|
68
|
+
.to raise_error(FinAppsCore::UserLockoutError, error_message)
|
69
|
+
}
|
38
70
|
end
|
39
71
|
end
|
40
72
|
end
|
@@ -1,96 +1,140 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe FinAppsCore::REST::BaseClient do
|
4
|
-
|
5
|
-
subject { FinAppsCore::REST::BaseClient.new(valid_tenant_options) }
|
4
|
+
subject(:base_client) { described_class.new(valid_tenant_options) }
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
let(:valid_tenant_options) { {tenant_token: VALID_CREDENTIALS[:token]} }
|
7
|
+
|
8
|
+
before do
|
9
|
+
stub_const 'RESPONSE', 0
|
10
|
+
stub_const 'ERROR_MESSAGES', 1
|
11
|
+
end
|
10
12
|
|
11
13
|
describe '#new' do
|
12
14
|
it 'assigns @config' do
|
13
|
-
expect(
|
15
|
+
expect(base_client.config).to be_a(FinAppsCore::REST::Configuration)
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
19
|
describe '#connection' do
|
18
20
|
it 'created a Faraday connection object' do
|
19
|
-
expect(
|
21
|
+
expect(base_client.connection).to be_a(Faraday::Connection)
|
20
22
|
end
|
21
23
|
|
22
24
|
it 'memoizes the results' do
|
23
|
-
first =
|
24
|
-
second =
|
25
|
+
first = base_client.connection
|
26
|
+
second = base_client.connection
|
25
27
|
expect(first.object_id).to eq(second.object_id)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
describe '#send_request' do
|
30
|
-
it '
|
31
|
-
expect {
|
32
|
-
|
32
|
+
it 'raises NoMethodError if method is NOT supported' do
|
33
|
+
expect { base_client.send_request('fake_path', :option) }
|
34
|
+
.to(raise_error(NoMethodError, /undefined method `option/))
|
33
35
|
end
|
34
36
|
|
35
|
-
it '
|
36
|
-
expect {
|
37
|
-
|
37
|
+
it 'raises FinAppsCore::MissingArgumentsError if method is NOT provided' do
|
38
|
+
expect { base_client.send_request(nil, :get) }
|
39
|
+
.to(raise_error(FinAppsCore::MissingArgumentsError, ': path'))
|
38
40
|
end
|
39
41
|
|
40
|
-
it '
|
41
|
-
expect {
|
42
|
-
|
42
|
+
it 'raises FinAppsCore::MissingArgumentsError if path is NOT provided' do
|
43
|
+
expect { base_client.send_request('fake_path', nil) }
|
44
|
+
.to raise_error(FinAppsCore::MissingArgumentsError, ': method')
|
43
45
|
end
|
44
46
|
|
45
47
|
context 'when method and path are provided' do
|
46
|
-
subject
|
47
|
-
|
48
|
+
subject(:results) do
|
49
|
+
described_class.new(valid_tenant_options)
|
50
|
+
.send_request('relevance/ruleset/names', :get)
|
51
|
+
end
|
52
|
+
|
53
|
+
it('returns an array') do
|
54
|
+
expect(results).to be_a(Array)
|
55
|
+
end
|
48
56
|
|
49
|
-
it('returns an array of 2
|
50
|
-
expect(
|
51
|
-
expect(subject.size).to eq(return_array.length)
|
57
|
+
it('returns an array of length=2') do
|
58
|
+
expect(results.size).to eq(2)
|
52
59
|
end
|
53
60
|
|
54
|
-
context '
|
55
|
-
subject
|
61
|
+
context 'with client errors' do
|
62
|
+
subject(:client_error) do
|
63
|
+
described_class.new(valid_tenant_options)
|
64
|
+
.send_request('client_error', :get)
|
65
|
+
end
|
56
66
|
|
57
|
-
it('result is null') { expect(
|
58
|
-
|
59
|
-
it('error_messages
|
67
|
+
it('result is null') { expect(client_error[RESPONSE]).to be_nil }
|
68
|
+
|
69
|
+
it('error_messages is an array') {
|
70
|
+
expect(client_error[ERROR_MESSAGES]).to be_a(Array)
|
71
|
+
}
|
72
|
+
|
73
|
+
it('error_messages gets populated') {
|
74
|
+
expect(client_error[ERROR_MESSAGES].first)
|
75
|
+
.to eq 'Password Minimum size is 8'
|
76
|
+
}
|
60
77
|
end
|
61
78
|
|
62
|
-
context '
|
63
|
-
subject
|
79
|
+
context 'with server errors' do
|
80
|
+
subject(:server_error) do
|
81
|
+
described_class.new(valid_tenant_options)
|
82
|
+
.send_request('server_error', :get)
|
83
|
+
end
|
84
|
+
|
85
|
+
it('the result should be nil') {
|
86
|
+
expect(server_error[RESPONSE]).to be_nil
|
87
|
+
}
|
88
|
+
|
89
|
+
it('error messages should not be nil') {
|
90
|
+
expect(server_error[ERROR_MESSAGES]).not_to be_nil
|
91
|
+
}
|
92
|
+
|
93
|
+
it('error messages should be an array') {
|
94
|
+
expect(server_error[ERROR_MESSAGES]).to be_a(Array)
|
95
|
+
}
|
64
96
|
|
65
|
-
it('the
|
66
|
-
|
67
|
-
|
68
|
-
|
97
|
+
it('the first error message should match') {
|
98
|
+
expect(server_error[ERROR_MESSAGES].first)
|
99
|
+
.to eq 'the server responded with status 500'
|
100
|
+
}
|
69
101
|
end
|
70
102
|
|
71
|
-
context '
|
72
|
-
subject
|
73
|
-
|
103
|
+
context 'with proxy errors' do
|
104
|
+
subject(:proxy_error) do
|
105
|
+
described_class.new(valid_tenant_options)
|
106
|
+
.send_request('proxy_error', :get)
|
107
|
+
end
|
108
|
+
|
109
|
+
it {
|
110
|
+
expect { proxy_error }
|
111
|
+
.to(raise_error(FinAppsCore::ConnectionFailedError,
|
112
|
+
'Connection Failed'))
|
113
|
+
}
|
74
114
|
end
|
75
115
|
end
|
76
116
|
|
77
|
-
context '
|
117
|
+
context 'when a block is provided' do
|
78
118
|
it('gets executed on the response and returned as the result') do
|
79
|
-
expect(
|
119
|
+
expect(base_client
|
120
|
+
.send_request('relevance/ruleset/names', :get) {|r| r.body.length })
|
121
|
+
.to eq([45, []])
|
80
122
|
end
|
81
123
|
end
|
82
124
|
end
|
83
125
|
|
84
126
|
describe '#method_missing' do
|
85
|
-
context '
|
86
|
-
it { expect {
|
127
|
+
context 'with unsupported methods' do
|
128
|
+
it { expect { base_client.unsupported }.to raise_error(NoMethodError) }
|
87
129
|
end
|
88
130
|
end
|
89
131
|
|
90
132
|
describe '#respond_to_missing?' do
|
91
|
-
context '
|
133
|
+
context 'with supported methods' do
|
92
134
|
%i[get post put delete].each do |method|
|
93
|
-
it("responds to #{method}") {
|
135
|
+
it("responds to #{method}") {
|
136
|
+
expect(base_client).to respond_to(method)
|
137
|
+
}
|
94
138
|
end
|
95
139
|
end
|
96
140
|
end
|
@@ -4,41 +4,48 @@ require 'finapps_core/error'
|
|
4
4
|
|
5
5
|
RSpec.describe FinAppsCore::REST::Configuration do
|
6
6
|
describe '#new' do
|
7
|
-
context '
|
8
|
-
subject {
|
7
|
+
context 'with invalid timeout configuration' do
|
8
|
+
subject(:configuration) { described_class.new(timeout: 'whatever') }
|
9
|
+
|
9
10
|
expected_error = FinAppsCore::InvalidArgumentsError
|
10
|
-
it { expect {
|
11
|
+
it { expect { configuration }.to raise_error(expected_error, 'Invalid argument. {timeout: whatever}') }
|
11
12
|
end
|
12
13
|
|
13
|
-
context '
|
14
|
-
subject {
|
15
|
-
|
16
|
-
|
14
|
+
context 'with missing timeout configuration' do
|
15
|
+
subject(:configuration) { described_class.new(timeout: nil) }
|
16
|
+
|
17
|
+
it 'has a default timeout value' do
|
18
|
+
expect(configuration.timeout).to eq(FinAppsCore::REST::Defaults::DEFAULTS[:timeout])
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
|
-
context '
|
21
|
-
subject {
|
22
|
+
context 'with invalid host configuration' do
|
23
|
+
subject(:configuration) { described_class.new(host: 'whatever') }
|
24
|
+
|
22
25
|
expected_error = FinAppsCore::InvalidArgumentsError
|
23
|
-
it { expect {
|
26
|
+
it { expect { configuration }.to raise_error(expected_error, 'Invalid argument. {host: whatever}') }
|
24
27
|
end
|
25
28
|
|
26
|
-
context '
|
27
|
-
subject {
|
28
|
-
|
29
|
-
|
29
|
+
context 'with missing host configuration' do
|
30
|
+
subject(:configuration) { described_class.new(host: nil) }
|
31
|
+
|
32
|
+
it 'has a default host value' do
|
33
|
+
expect(configuration.host).to eq(FinAppsCore::REST::Defaults::DEFAULTS[:host])
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
38
|
describe '#valid_user_credentials??' do
|
35
39
|
context 'when user credentials were not set' do
|
36
|
-
subject {
|
37
|
-
|
40
|
+
subject(:configuration) { described_class.new(host: nil) }
|
41
|
+
|
42
|
+
it { expect(configuration.valid_user_credentials?).to eq(false) }
|
38
43
|
end
|
44
|
+
|
39
45
|
context 'when user credentials were set' do
|
40
|
-
subject {
|
41
|
-
|
46
|
+
subject(:configuration) { described_class.new(user_identifier: 1, user_token: 2) }
|
47
|
+
|
48
|
+
it { expect(configuration.valid_user_credentials?).to eq(true) }
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|