roqua-healthy 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +18 -0
- data/.rubocop.yml +1 -1
- data/Gemfile +3 -0
- data/lib/roqua/errors.rb +0 -0
- data/lib/roqua/healthy.rb +1 -0
- data/lib/roqua/healthy/a19/fetcher.rb +7 -11
- data/lib/roqua/healthy/a19/response_validator.rb +1 -16
- data/lib/roqua/healthy/errors.rb +30 -0
- data/lib/roqua/healthy/oru.rb +10 -0
- data/lib/roqua/healthy/oru/client.rb +45 -0
- data/lib/roqua/healthy/version.rb +1 -1
- data/spec/unit/oru/client_spec.rb +131 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72774ae40a9addc4ac31ab7ee7470b9ad251bf5f
|
4
|
+
data.tar.gz: 4f867af413282b3ac97041bd8a56b5f95a492025
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48b2c55af9044ccc8395c87d71e9e1d4f201f98643646f0f70fdd5b2fabbe3d200293e61a6607909b52d9cdd533fc6cc3f285d2026a39b98218a270b03c51eb8
|
7
|
+
data.tar.gz: 6034a23f518d4db1d59aa7430c5c0ad594312f0e6bd50f09c50a1eb87828742f01cf8eb7de42eddac596c9aabc6a0201ee93ac4e9ab47e540a4999d8a9fa2451
|
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
image: "roqua/roqua-build-images:ruby-2.3.3-phantomjs-2.1.1-bundler-gemnasium"
|
2
|
+
|
3
|
+
before_script:
|
4
|
+
- ruby -v
|
5
|
+
- bundle-cache
|
6
|
+
- gem install appraisal
|
7
|
+
- bundle exec appraisal
|
8
|
+
|
9
|
+
rubocop:
|
10
|
+
script:
|
11
|
+
- bundle exec rubocop -D
|
12
|
+
|
13
|
+
rspec:
|
14
|
+
script:
|
15
|
+
- bundle exec appraisal rails41 bundle exec rspec
|
16
|
+
- bundle exec appraisal rails42 bundle exec rspec
|
17
|
+
- bundle exec appraisal rails50 bundle exec rspec
|
18
|
+
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/lib/roqua/errors.rb
ADDED
File without changes
|
data/lib/roqua/healthy.rb
CHANGED
@@ -25,18 +25,14 @@ module Roqua
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def mirth_response
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
Roqua::Healthy.convert_generic_errors_to_healthy_errors do
|
29
|
+
Net::HTTP.start(remote_url.host, remote_url.port, use_ssl: use_ssl?) do |http|
|
30
|
+
request = Net::HTTP::Post.new(remote_url.path)
|
31
|
+
request.basic_auth(@client.a19_username, @client.a19_password) if @client.use_basic_auth?
|
32
|
+
request.set_form_data(mirth_params)
|
33
|
+
http.request request
|
34
|
+
end
|
33
35
|
end
|
34
|
-
rescue ::Timeout::Error, Errno::ETIMEDOUT => error
|
35
|
-
raise ::Roqua::Healthy::Timeout, error.message
|
36
|
-
rescue Errno::EHOSTUNREACH => error
|
37
|
-
raise ::Roqua::Healthy::HostUnreachable, error.message
|
38
|
-
rescue Errno::ECONNREFUSED => error
|
39
|
-
raise ::Roqua::Healthy::ConnectionRefused, error.message
|
40
36
|
end
|
41
37
|
|
42
38
|
private
|
@@ -11,21 +11,6 @@ module Roqua
|
|
11
11
|
attr_reader :parser
|
12
12
|
attr_reader :patient_id
|
13
13
|
|
14
|
-
ERRORS = {
|
15
|
-
'Timeout waiting for ACK' =>
|
16
|
-
::Roqua::Healthy::Timeout,
|
17
|
-
"Unable to connect to destination\tSocketTimeoutException\tconnect timed out" =>
|
18
|
-
::Roqua::Healthy::Timeout,
|
19
|
-
'ERROR: Timeout waiting for response' =>
|
20
|
-
::Roqua::Healthy::Timeout,
|
21
|
-
'ERROR: SocketTimeoutException: connect timed out' =>
|
22
|
-
::Roqua::Healthy::Timeout,
|
23
|
-
"Unable to connect to destination\tConnectException\tConnection refused" =>
|
24
|
-
::Roqua::Healthy::ConnectionRefused,
|
25
|
-
'ERROR: ConnectException: Connection refused' =>
|
26
|
-
::Roqua::Healthy::ConnectionRefused
|
27
|
-
}.freeze
|
28
|
-
|
29
14
|
def initialize(response_code, parser, patient_id)
|
30
15
|
@response_code = response_code
|
31
16
|
@parser = parser
|
@@ -64,7 +49,7 @@ module Roqua
|
|
64
49
|
|
65
50
|
def validate_500
|
66
51
|
error = parser.fetch('failure')['error']
|
67
|
-
raise ERRORS[error], error if ERRORS[error]
|
52
|
+
raise ::Roqua::Healthy::ERRORS[error], error if ::Roqua::Healthy::ERRORS[error]
|
68
53
|
raise ::Roqua::Healthy::UnknownFailure, error
|
69
54
|
end
|
70
55
|
|
data/lib/roqua/healthy/errors.rb
CHANGED
@@ -3,6 +3,7 @@ module Roqua
|
|
3
3
|
module Healthy
|
4
4
|
class Error < StandardError; end
|
5
5
|
class ConnectionError < Error; end
|
6
|
+
class NACK < Error; end
|
6
7
|
|
7
8
|
class IllegalMirthResponse < ConnectionError; end
|
8
9
|
class Timeout < ConnectionError; end
|
@@ -17,5 +18,34 @@ module Roqua
|
|
17
18
|
module MirthErrors
|
18
19
|
class WrongPatient < Error; end
|
19
20
|
end
|
21
|
+
|
22
|
+
def self.convert_generic_errors_to_healthy_errors
|
23
|
+
yield
|
24
|
+
rescue RestClient::Exceptions::ReadTimeout, RestClient::Exceptions::OpenTimeout => error
|
25
|
+
raise ::Roqua::Healthy::Timeout, error.message
|
26
|
+
rescue ::Timeout::Error => error
|
27
|
+
raise ::Roqua::Healthy::Timeout, error.message
|
28
|
+
rescue Errno::ETIMEDOUT => error
|
29
|
+
raise ::Roqua::Healthy::Timeout, error.message
|
30
|
+
rescue Errno::EHOSTUNREACH => error
|
31
|
+
raise ::Roqua::Healthy::HostUnreachable, error.message
|
32
|
+
rescue Errno::ECONNREFUSED => error
|
33
|
+
raise ::Roqua::Healthy::ConnectionRefused, error.message
|
34
|
+
end
|
35
|
+
|
36
|
+
ERRORS = {
|
37
|
+
'Timeout waiting for ACK' =>
|
38
|
+
::Roqua::Healthy::Timeout,
|
39
|
+
"Unable to connect to destination\tSocketTimeoutException\tconnect timed out" =>
|
40
|
+
::Roqua::Healthy::Timeout,
|
41
|
+
'ERROR: Timeout waiting for response' =>
|
42
|
+
::Roqua::Healthy::Timeout,
|
43
|
+
'ERROR: SocketTimeoutException: connect timed out' =>
|
44
|
+
::Roqua::Healthy::Timeout,
|
45
|
+
"Unable to connect to destination\tConnectException\tConnection refused" =>
|
46
|
+
::Roqua::Healthy::ConnectionRefused,
|
47
|
+
'ERROR: ConnectException: Connection refused' =>
|
48
|
+
::Roqua::Healthy::ConnectionRefused
|
49
|
+
}.freeze
|
20
50
|
end
|
21
51
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'rest-client'
|
5
|
+
|
6
|
+
module Roqua
|
7
|
+
module Healthy
|
8
|
+
module Oru
|
9
|
+
class Client
|
10
|
+
def self.execute(url, data, timeout:)
|
11
|
+
Roqua::Healthy.convert_generic_errors_to_healthy_errors do
|
12
|
+
deliver_data(url, data, timeout: timeout)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.deliver_data(url, data, timeout:)
|
17
|
+
xml = CGI.escape(data.to_xml)
|
18
|
+
RestClient::Request.execute(
|
19
|
+
method: :post,
|
20
|
+
url: url.to_s,
|
21
|
+
payload: xml,
|
22
|
+
headers: {content_type: 'text/xml'},
|
23
|
+
timeout: timeout.to_i
|
24
|
+
) do |response, _request, _result|
|
25
|
+
|
26
|
+
xml_response = Hash.from_xml(response.body)
|
27
|
+
|
28
|
+
if response.code == 200 && xml_response['oru']['status'] == 'ACK'
|
29
|
+
response.body
|
30
|
+
else
|
31
|
+
handle_error(response, xml_response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.handle_error(response, xml_response)
|
37
|
+
error = xml_response.dig('oru', 'error')
|
38
|
+
raise ::Roqua::Healthy::ERRORS[error], error if ::Roqua::Healthy::ERRORS[error]
|
39
|
+
raise ::Roqua::Healthy::NACK, error if error.present?
|
40
|
+
raise ::Roqua::Healthy::UnknownFailure, response.body
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Roqua::Healthy::Oru::Client do
|
5
|
+
def stub_oru_response(status, body = '<oru><status>ACK</status></oru>')
|
6
|
+
stub_request(:post, oru_url)
|
7
|
+
.with(
|
8
|
+
body: \
|
9
|
+
'%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%0A%3C' \
|
10
|
+
'hash%3E%0A++%3Coru+type%3D%22symbol%22%3Edata%3C%2Foru%3E%0A%3C%2Fhash%3E%0A',
|
11
|
+
headers: {
|
12
|
+
'Accept' => '*/*',
|
13
|
+
'Accept-Encoding' => 'gzip, deflate',
|
14
|
+
'Content-Length' => '140',
|
15
|
+
'Content-Type' => 'text/xml'
|
16
|
+
}
|
17
|
+
)
|
18
|
+
.to_return(status: status, body: body, headers: {})
|
19
|
+
end
|
20
|
+
|
21
|
+
def stub_500_response
|
22
|
+
stub_request(:post, oru_url)
|
23
|
+
.to_return(status: 500, body: '<oru><status>NACK</status><error>ERROR</error></oru>', headers: {})
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_404_response
|
27
|
+
stub_request(:post, oru_url)
|
28
|
+
.to_return(status: 404, body: '<oru><status>NACK</status><error>ERROR</error></oru>', headers: {})
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:subject) { Roqua::Healthy::Oru::Client }
|
32
|
+
let(:oru_url) { 'https://example.com' }
|
33
|
+
let(:timeout) { 5.seconds }
|
34
|
+
|
35
|
+
def execute_request
|
36
|
+
subject.execute(oru_url, {oru: :data}, timeout: timeout)
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when Errno::ETIMEDOUT is triggered' do
|
40
|
+
it 'will raise an ::Roqua::Healthy::Timeout exception' do
|
41
|
+
expect(Roqua::Healthy::Oru::Client).to receive(:deliver_data).and_raise(Errno::ETIMEDOUT)
|
42
|
+
expect { execute_request }.to raise_error(::Roqua::Healthy::Timeout)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'sets the correct timeout' do
|
47
|
+
expect(RestClient::Request).to receive(:execute).with(
|
48
|
+
method: :post,
|
49
|
+
url: 'https://example.com',
|
50
|
+
payload: '%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%0A%3Chash%3E%0A++%3C' \
|
51
|
+
'oru+type%3D%22symbol%22%3Edata%3C%2Foru%3E%0A%3C%2Fhash%3E%0A',
|
52
|
+
headers: {content_type: 'text/xml'},
|
53
|
+
timeout: timeout.to_i
|
54
|
+
).and_return(double(body: '<oru><status>ACK</status></oru>'))
|
55
|
+
|
56
|
+
execute_request
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when upstream is responding" do
|
60
|
+
it "does not raise an exception" do
|
61
|
+
stub_oru_response 200, '<oru><status>ACK</status></oru>'
|
62
|
+
execute_request
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when a nack is received' do
|
66
|
+
before { stub_oru_response 200, '<oru><status>NACK</status><error>NACK</error></oru>' }
|
67
|
+
|
68
|
+
it 'raises a NACK exception' do
|
69
|
+
expect { execute_request }.to raise_error(Roqua::Healthy::NACK)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when upstream is giving connection refused" do
|
75
|
+
before do
|
76
|
+
stub_request(:any, oru_url).to_raise Errno::ECONNREFUSED
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise Oru::ConnectionRefused" do
|
80
|
+
expect { execute_request }.to raise_exception(Roqua::Healthy::ConnectionRefused)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when upstream is giving connection timeouts" do
|
85
|
+
before do
|
86
|
+
stub_request(:any, oru_url).to_timeout
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should raise Oru::Timeout" do
|
90
|
+
expect { execute_request }.to raise_exception(Roqua::Healthy::Timeout)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when upstream is giving waiting for ack timeouts" do
|
95
|
+
before do
|
96
|
+
stub_oru_response \
|
97
|
+
500,
|
98
|
+
"<oru><status>FAILURE</status><channel>RGOC - Outbound port 60102</channel>" \
|
99
|
+
"<error>Timeout waiting for ACK</error></oru>"
|
100
|
+
end
|
101
|
+
|
102
|
+
it "raises a NACK exception" do
|
103
|
+
expect { execute_request }.to raise_error(::Roqua::Healthy::Timeout, /Timeout waiting for ACK/)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when upstream responds with a 500 status' do
|
108
|
+
before { stub_500_response }
|
109
|
+
|
110
|
+
it 'transforms the exception to a NACK' do
|
111
|
+
expect { execute_request }.to raise_error Roqua::Healthy::NACK
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when upstream responds with a 404 status' do
|
116
|
+
before { stub_404_response }
|
117
|
+
|
118
|
+
it 'transforms the exception to a NACK' do
|
119
|
+
expect { execute_request }.to raise_error Roqua::Healthy::NACK
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when the response doesn't contain an error portion" do
|
124
|
+
it 'will raise a ... exception' do
|
125
|
+
stub_request(:post, oru_url)
|
126
|
+
.to_return(status: 500, body: '<oru><status>Internal server error</status></oru>', headers: {})
|
127
|
+
|
128
|
+
expect { execute_request }.to raise_error Roqua::Healthy::UnknownFailure
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roqua-healthy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marten Veldthuis
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-
|
14
|
+
date: 2017-07-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -266,6 +266,7 @@ extra_rdoc_files: []
|
|
266
266
|
files:
|
267
267
|
- ".document"
|
268
268
|
- ".gitignore"
|
269
|
+
- ".gitlab-ci.yml"
|
269
270
|
- ".rspec"
|
270
271
|
- ".rubocop.yml"
|
271
272
|
- ".rubocop_todo.yml"
|
@@ -285,6 +286,7 @@ files:
|
|
285
286
|
- gemfiles/rails41.gemfile
|
286
287
|
- gemfiles/rails42.gemfile
|
287
288
|
- gemfiles/rails50.gemfile
|
289
|
+
- lib/roqua/errors.rb
|
288
290
|
- lib/roqua/healthy.rb
|
289
291
|
- lib/roqua/healthy/a19.rb
|
290
292
|
- lib/roqua/healthy/a19/address_parser.rb
|
@@ -299,6 +301,8 @@ files:
|
|
299
301
|
- lib/roqua/healthy/client.rb
|
300
302
|
- lib/roqua/healthy/errors.rb
|
301
303
|
- lib/roqua/healthy/message_cleaner.rb
|
304
|
+
- lib/roqua/healthy/oru.rb
|
305
|
+
- lib/roqua/healthy/oru/client.rb
|
302
306
|
- lib/roqua/healthy/version.rb
|
303
307
|
- lib/roqua_healthy.rb
|
304
308
|
- roqua-healthy.gemspec
|
@@ -350,6 +354,7 @@ files:
|
|
350
354
|
- spec/unit/a19_spec.rb
|
351
355
|
- spec/unit/client_spec.rb
|
352
356
|
- spec/unit/message_cleaner_spec.rb
|
357
|
+
- spec/unit/oru/client_spec.rb
|
353
358
|
homepage: https://github.com/roqua/healthy
|
354
359
|
licenses:
|
355
360
|
- MIT
|
@@ -423,3 +428,4 @@ test_files:
|
|
423
428
|
- spec/unit/a19_spec.rb
|
424
429
|
- spec/unit/client_spec.rb
|
425
430
|
- spec/unit/message_cleaner_spec.rb
|
431
|
+
- spec/unit/oru/client_spec.rb
|