-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jmax/lg 15676 passport api health check infrastructure #11891
base: main
Are you sure you want to change the base?
Changes from 15 commits
7bfff01
15e1ff1
0ef310d
f84be15
8e5f6f7
8adbfc0
aca8a66
4587495
427fdfb
916a501
62380cc
033ae4a
4acc77c
d5efe7c
b4ed521
4f90570
aba3764
f772c2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
module Dos | ||
module Requests | ||
class HealthCheckRequest | ||
def fetch(analytics) | ||
begin | ||
faraday_response = connection.get | ||
response = Responses::HealthCheckSuccess.new(faraday_response) | ||
rescue Faraday::Error => faraday_error | ||
response = Responses::HealthCheckFailure.new(faraday_error) | ||
end | ||
ensure | ||
analytics.passport_api_health_check( | ||
success: response.success?, | ||
**response.extra, | ||
) | ||
end | ||
|
||
private | ||
|
||
attr_reader :analytics | ||
|
||
def connection | ||
@connection ||= Faraday::Connection.new( | ||
url: IdentityConfig.store.passports_api_health_check_endpoint, | ||
) do |builder| | ||
builder.response :raise_error | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
module Dos | ||
module Responses | ||
class HealthCheckFailure < DocAuth::Response | ||
def initialize(faraday_error) | ||
errors = | ||
if faraday_error.respond_to?(:status) # some subclasses don't | ||
{ network: faraday_error.status } | ||
else | ||
{ network: true } | ||
end | ||
|
||
super( | ||
success: false, | ||
errors:, | ||
exception: faraday_error, | ||
extra: { error: faraday_error.inspect } | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
module Dos | ||
module Responses | ||
class HealthCheckSuccess < DocAuth::Response | ||
def initialize(faraday_response) | ||
extra = | ||
if faraday_response.body && !faraday_response.body.empty? | ||
{ body: faraday_response.body } | ||
else | ||
{} | ||
end | ||
|
||
super( | ||
success: faraday_response.success?, | ||
extra: | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this file to be deleted after namespace change? |
||
module Passports | ||
module Dos | ||
module Requests | ||
class HealthCheckRequest | ||
def initialize(analytics:) | ||
@analytics = analytics | ||
end | ||
|
||
def fetch | ||
begin | ||
faraday_response = connection.get | ||
response = Responses::HealthCheckSuccess.new(faraday_response) | ||
rescue Faraday::Error => faraday_error | ||
response = Responses::HealthCheckFailure.new(faraday_error) | ||
end | ||
ensure | ||
analytics.passport_api_health_check( | ||
success: response.success?, | ||
**response.extra, | ||
) | ||
end | ||
|
||
private | ||
|
||
attr_reader :analytics | ||
|
||
def connection | ||
@connection ||= Faraday::Connection.new( | ||
url: IdentityConfig.store.passports_api_health_check_endpoint, | ||
) do |builder| | ||
builder.response :raise_error | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
module Passports | ||
module Dos | ||
module Responses | ||
class HealthCheckFailure < DocAuth::Response | ||
def initialize(faraday_error) | ||
errors = | ||
if faraday_error.respond_to?(:status) # some subclasses don't | ||
{ network: faraday_error.status } | ||
else | ||
{ network: true } | ||
end | ||
|
||
super( | ||
success: false, | ||
errors:, | ||
exception: faraday_error, | ||
extra: { error: faraday_error.inspect } | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
module DocAuth | ||
module Passports | ||
module Dos | ||
module Responses | ||
class HealthCheckSuccess < DocAuth::Response | ||
def initialize(faraday_response) | ||
extra = | ||
if faraday_response.body && !faraday_response.body.empty? | ||
{ body: faraday_response.body } | ||
else | ||
{} | ||
end | ||
|
||
super( | ||
success: faraday_response.success?, | ||
extra: | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -285,6 +285,7 @@ outbound_connection_check_retry_count: 2 | |||
outbound_connection_check_timeout: 5 | ||||
outbound_connection_check_url: 'https://checkip.amazonaws.com' | ||||
participate_in_dap: false | ||||
passports_api_health_check_endpoint: 'https://caapinpe.state.gov/api/passport-match-prc-api/v1/html' | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
password_max_attempts: 3 | ||||
password_pepper: | ||||
personal_key_retired: true | ||||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -313,6 +313,7 @@ def self.store | |||
config.add(:outbound_connection_check_timeout, type: :integer) | ||||
config.add(:outbound_connection_check_url) | ||||
config.add(:participate_in_dap, type: :boolean) | ||||
config.add(:passports_api_health_check_endpoint, type: :string) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
config.add(:password_max_attempts, type: :integer) | ||||
config.add(:password_pepper, type: :string) | ||||
config.add(:personal_key_retired, type: :boolean) | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe DocAuth::Dos::Requests::HealthCheckRequest do | ||
include PassportApiHelpers | ||
|
||
subject(:health_check_request) { described_class.new } | ||
|
||
let(:analytics) { FakeAnalytics.new } | ||
|
||
let(:health_check_endpoint) do | ||
IdentityConfig.store.passports_api_health_check_endpoint | ||
end | ||
|
||
describe '#fetch' do | ||
let(:result) { health_check_request.fetch(analytics) } | ||
|
||
context 'happy path' do | ||
before do | ||
stub_api_up | ||
end | ||
|
||
it 'hits the endpoint' do | ||
result | ||
expect(WebMock).to have_requested(:get, health_check_endpoint) | ||
end | ||
|
||
it 'logs the request' do | ||
result | ||
expect(analytics).to have_logged_event( | ||
:passport_api_health_check, | ||
success: true, | ||
body: successful_api_health_check_body.to_json, | ||
) | ||
end | ||
|
||
describe 'the #fetch result' do | ||
it 'succeeds' do | ||
expect(result).to be_success | ||
end | ||
end | ||
end | ||
|
||
context 'when Faraday raises an error' do | ||
before do | ||
stub_request(:get, health_check_endpoint).to_raise(Faraday::Error) | ||
end | ||
|
||
it 'hits the endpoint' do | ||
result | ||
expect(WebMock).to have_requested(:get, health_check_endpoint) | ||
end | ||
|
||
it 'logs the request' do | ||
result | ||
expect(analytics).to have_logged_event( | ||
:passport_api_health_check, | ||
success: false, | ||
error: /Faraday::Error/, | ||
) | ||
end | ||
|
||
describe 'the #fetch result' do | ||
it 'does not succeed' do | ||
expect(result).not_to be_success | ||
end | ||
end | ||
end | ||
|
||
context 'when Faraday returns an HTTP error' do | ||
before do | ||
stub_request(:get, health_check_endpoint).to_return(status: 500) | ||
end | ||
|
||
it 'hits the endpoint' do | ||
result | ||
expect(WebMock).to have_requested(:get, health_check_endpoint) | ||
end | ||
|
||
it 'logs the request' do | ||
result | ||
expect(analytics).to have_logged_event( | ||
:passport_api_health_check, | ||
success: false, | ||
error: /Faraday::ServerError/, | ||
) | ||
end | ||
|
||
describe 'the #fetch result' do | ||
it 'does not succeed' do | ||
expect(result).not_to be_success | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe DocAuth::Dos::Responses::HealthCheckFailure do | ||
subject(:health_check_result) { described_class.new(faraday_error) } | ||
|
||
let(:health_check_endpoint) do | ||
IdentityConfig.store.passports_api_health_check_endpoint | ||
end | ||
|
||
def make_faraday_error(status:) | ||
stub_request(:get, health_check_endpoint).to_return(status:) | ||
begin | ||
Faraday.get(health_check_endpoint) | ||
rescue FaradayError => faraday_error | ||
faraday_error | ||
end | ||
end | ||
|
||
[403, 404, 500].each do |http_status| | ||
context "when initialized from an HTTP #{http_status} error" do | ||
let(:faraday_error) { make_faraday_error(status: http_status) } | ||
|
||
it 'is not successful' do | ||
expect(health_check_result).not_to be_success | ||
end | ||
|
||
it 'has the correct errors hash' do | ||
expect(health_check_result.errors).to eq({ network: http_status }) | ||
end | ||
|
||
it 'has the faraday exception' do | ||
expect(health_check_result.exception).to eq(faraday_error) | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are 2 healthcheck endpoints for which we need to be able to check ...
there is also a composite healthcheck endpoint