From de681f2a3483f49ec8443ce323feeda1eb7ace99 Mon Sep 17 00:00:00 2001 From: Ralph Wort Date: Tue, 7 May 2024 14:12:41 +0100 Subject: [PATCH] working through services/nomis --- app/services/nomis/api_enabled_guard.rb | 43 --- app/services/nomis/availability_visit.rb | 8 - app/services/nomis/cancellation.rb | 11 - app/services/nomis/code.rb | 8 - app/services/nomis/contact.rb | 53 ---- app/services/nomis/contact/contact_type.rb | 6 - app/services/nomis/contact/gender.rb | 6 - app/services/nomis/contact/relationship.rb | 6 - app/services/nomis/contact_list.rb | 19 -- app/services/nomis/error/disabled.rb | 7 - app/services/nomis/error/not_found.rb | 7 - .../nomis/error/unhandled_api_field.rb | 7 - app/services/nomis/establishment.rb | 18 -- app/services/nomis/feature.rb | 12 - app/services/nomis/housing_location.rb | 8 - app/services/nomis/housing_location/level.rb | 10 - app/services/nomis/prisoner/details.rb | 33 --- .../nomis/prisoner_date_availability.rb | 33 --- .../nomis/prisoner_detailed_availability.rb | 33 --- app/services/nomis/restriction.rb | 31 -- app/services/nomis/restriction/type.rb | 6 - app/services/nomis/visit_order.rb | 8 - spec/fixtures/vcr_cassettes/client-auth.yml | 103 +++++++ .../vcr_cassettes/client-request-id.yml | 152 ++++++++++ .../vcr_cassettes/fetch_contact_list.yml | 103 +++++++ .../vcr_cassettes/lookup_active_prisoner.yml | 103 +++++++ .../lookup_active_prisoner_nomatch.yml | 103 +++++++ ...ookup_offender_details_invalid_noms_id.yml | 103 +++++++ .../vcr_cassettes/lookup_prisoner_details.yml | 103 +++++++ ...okup_prisoner_details_unknown_prisoner.yml | 103 +++++++ .../lookup_prisoner_location.yml | 103 +++++++ ...p_prisoner_location_for_bogus_prisoner.yml | 103 +++++++ ...prisoner_location_for_unknown_prisoner.yml | 103 +++++++ .../vcr_cassettes/nomis_oauth_jwks.yml | 37 +++ .../prisoner_visiting_availability.yml | 103 +++++++ ...r_visiting_availability_noavailability.yml | 103 +++++++ ...risoner_visiting_detailed_availability.yml | 103 +++++++ spec/services/nomis/api_serialiser_spec.rb | 26 ++ .../nomis/api_slot_normaliser_spec.rb | 40 +++ spec/services/nomis/api_slot_spec.rb | 30 ++ spec/services/nomis/api_spec.rb | 271 ++++++++++++++++++ spec/services/nomis/client_spec.rb | 161 +++++++++++ spec/services/nomis/null_prisoner_spec.rb | 6 + spec/services/nomis/oauth/client_spec.rb | 57 ++++ .../services/nomis/oauth/jwks_service_spec.rb | 20 ++ .../nomis/oauth/token_service_spec.rb | 24 ++ spec/services/nomis/prisoner_spec.rb | 77 +++++ 47 files changed, 2240 insertions(+), 373 deletions(-) delete mode 100644 app/services/nomis/api_enabled_guard.rb delete mode 100644 app/services/nomis/availability_visit.rb delete mode 100644 app/services/nomis/cancellation.rb delete mode 100644 app/services/nomis/code.rb delete mode 100644 app/services/nomis/contact.rb delete mode 100644 app/services/nomis/contact/contact_type.rb delete mode 100644 app/services/nomis/contact/gender.rb delete mode 100644 app/services/nomis/contact/relationship.rb delete mode 100644 app/services/nomis/contact_list.rb delete mode 100644 app/services/nomis/error/disabled.rb delete mode 100644 app/services/nomis/error/not_found.rb delete mode 100644 app/services/nomis/error/unhandled_api_field.rb delete mode 100644 app/services/nomis/establishment.rb delete mode 100644 app/services/nomis/feature.rb delete mode 100644 app/services/nomis/housing_location.rb delete mode 100644 app/services/nomis/housing_location/level.rb delete mode 100644 app/services/nomis/prisoner/details.rb delete mode 100644 app/services/nomis/prisoner_date_availability.rb delete mode 100644 app/services/nomis/prisoner_detailed_availability.rb delete mode 100644 app/services/nomis/restriction.rb delete mode 100644 app/services/nomis/restriction/type.rb delete mode 100644 app/services/nomis/visit_order.rb create mode 100644 spec/fixtures/vcr_cassettes/client-auth.yml create mode 100644 spec/fixtures/vcr_cassettes/client-request-id.yml create mode 100644 spec/fixtures/vcr_cassettes/fetch_contact_list.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_active_prisoner.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_active_prisoner_nomatch.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_offender_details_invalid_noms_id.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_prisoner_details.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_prisoner_details_unknown_prisoner.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_prisoner_location.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_bogus_prisoner.yml create mode 100644 spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_unknown_prisoner.yml create mode 100644 spec/fixtures/vcr_cassettes/nomis_oauth_jwks.yml create mode 100644 spec/fixtures/vcr_cassettes/prisoner_visiting_availability.yml create mode 100644 spec/fixtures/vcr_cassettes/prisoner_visiting_availability_noavailability.yml create mode 100644 spec/fixtures/vcr_cassettes/prisoner_visiting_detailed_availability.yml create mode 100644 spec/services/nomis/api_serialiser_spec.rb create mode 100644 spec/services/nomis/api_slot_normaliser_spec.rb create mode 100644 spec/services/nomis/api_slot_spec.rb create mode 100644 spec/services/nomis/api_spec.rb create mode 100644 spec/services/nomis/client_spec.rb create mode 100644 spec/services/nomis/null_prisoner_spec.rb create mode 100644 spec/services/nomis/oauth/client_spec.rb create mode 100644 spec/services/nomis/oauth/jwks_service_spec.rb create mode 100644 spec/services/nomis/oauth/token_service_spec.rb create mode 100644 spec/services/nomis/prisoner_spec.rb diff --git a/app/services/nomis/api_enabled_guard.rb b/app/services/nomis/api_enabled_guard.rb deleted file mode 100644 index d90d7c12..00000000 --- a/app/services/nomis/api_enabled_guard.rb +++ /dev/null @@ -1,43 +0,0 @@ -module Nomis - module ApiEnabledGuard - def self.included(base) - base.extend ClassMethods - base.const_set('NOT_LIVE', 'not_live'.freeze) - end - - module ClassMethods - def method_added(method_name) - if wrap_method?(method_name) - api_method = instance_method method_name - method_redefined << method_name - - define_method method_name do |*args| - return self.class::NOT_LIVE unless Nomis::Api.enabled? - - api_method.bind_call(self, *args) - end - end - - @wrap_next_method_definition = false - end - - private - - def wrap_method?(method_name) - wrap_next_method_definition && !method_redefined.include?(method_name) - end - - def method_redefined - @method_redefined ||= [] - end - - def check_nomis_enabled - @wrap_next_method_definition = true - end - - def wrap_next_method_definition - @wrap_next_method_definition ||= false - end - end - end -end diff --git a/app/services/nomis/availability_visit.rb b/app/services/nomis/availability_visit.rb deleted file mode 100644 index 2952e042..00000000 --- a/app/services/nomis/availability_visit.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Nomis - class AvailabilityVisit - include MemoryModel - - attribute :slot, :normalised_concrete_slot - attribute :id, :string - end -end diff --git a/app/services/nomis/cancellation.rb b/app/services/nomis/cancellation.rb deleted file mode 100644 index 1cc253f7..00000000 --- a/app/services/nomis/cancellation.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Nomis - class Cancellation - include MemoryModel - attribute :message, :string - attribute :error_message, :string - - def error=(error) - self.error_message = error['message'] - end - end -end diff --git a/app/services/nomis/code.rb b/app/services/nomis/code.rb deleted file mode 100644 index e62093ac..00000000 --- a/app/services/nomis/code.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Nomis - class Code - include MemoryModel - - attribute :code, :string - attribute :desc, :string - end -end diff --git a/app/services/nomis/contact.rb b/app/services/nomis/contact.rb deleted file mode 100644 index 6e5b925b..00000000 --- a/app/services/nomis/contact.rb +++ /dev/null @@ -1,53 +0,0 @@ -module Nomis - class Contact - include MemoryModel - include Comparable - - attribute :id, :integer - attribute :given_name, :string - attribute :middle_names, :string - attribute :surname, :string - attribute :date_of_birth, :date - attribute :gender, :contact_gender - attribute :relationship_type, :contact_relationship - attribute :contact_type, :contact_type - attribute :approved_visitor, :boolean - attribute :active, :boolean - attribute :restrictions, :restriction_list - - def attributes - { - 'id' => id, - 'given_name' => given_name, - 'surname' => surname, - 'date_of_birth' => date_of_birth, - 'gender' => gender, - 'relationship_type' => relationship_type, - 'contact_type' => contact_type, - 'approved_visitor' => approved_visitor, - 'active' => active, - 'restrictions' => restrictions - } - end - - def full_name - "#{given_name} #{surname}".downcase - end - - def approved? - approved_visitor - end - - def banned? - restrictions.any?(&:banned?) - end - - def banned_until - restrictions.find(&:banned?)&.expiry_date - end - - def <=>(other) - [surname, given_name] <=> [other.surname, other.given_name] - end - end -end diff --git a/app/services/nomis/contact/contact_type.rb b/app/services/nomis/contact/contact_type.rb deleted file mode 100644 index 62b1ca51..00000000 --- a/app/services/nomis/contact/contact_type.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Nomis - class Contact - class ContactType < Code - end - end -end diff --git a/app/services/nomis/contact/gender.rb b/app/services/nomis/contact/gender.rb deleted file mode 100644 index 14cb64bc..00000000 --- a/app/services/nomis/contact/gender.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Nomis - class Contact - class Gender < Code - end - end -end diff --git a/app/services/nomis/contact/relationship.rb b/app/services/nomis/contact/relationship.rb deleted file mode 100644 index c581d234..00000000 --- a/app/services/nomis/contact/relationship.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Nomis - class Contact - class Relationship < Code - end - end -end diff --git a/app/services/nomis/contact_list.rb b/app/services/nomis/contact_list.rb deleted file mode 100644 index b8bae271..00000000 --- a/app/services/nomis/contact_list.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Nomis - class ContactList - include MemoryModel - include Enumerable - - delegate :each, to: :contacts - - attribute :contacts, :contacts_enumerable, default: [] - attribute :api_call_successful, :boolean, default: true - - def approved - select(&:approved?) - end - - def api_call_successful? - api_call_successful - end - end -end diff --git a/app/services/nomis/error/disabled.rb b/app/services/nomis/error/disabled.rb deleted file mode 100644 index 175f61b8..00000000 --- a/app/services/nomis/error/disabled.rb +++ /dev/null @@ -1,7 +0,0 @@ -# :nocov: -module Nomis - class Error - class Disabled < Error; end - end -end -# :nocov: diff --git a/app/services/nomis/error/not_found.rb b/app/services/nomis/error/not_found.rb deleted file mode 100644 index 98ec5f4d..00000000 --- a/app/services/nomis/error/not_found.rb +++ /dev/null @@ -1,7 +0,0 @@ -# :nocov: -module Nomis - class Error - class NotFound < Error; end - end -end -# :nocov: diff --git a/app/services/nomis/error/unhandled_api_field.rb b/app/services/nomis/error/unhandled_api_field.rb deleted file mode 100644 index 9dbee2df..00000000 --- a/app/services/nomis/error/unhandled_api_field.rb +++ /dev/null @@ -1,7 +0,0 @@ -# :nocov: -module Nomis - class Error - class UnhandledApiField < Error; end - end -end -# :nocov: diff --git a/app/services/nomis/establishment.rb b/app/services/nomis/establishment.rb deleted file mode 100644 index 83577cd2..00000000 --- a/app/services/nomis/establishment.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Nomis - class Establishment < Code - attribute :api_call_successful, :boolean, default: true - attribute :housing_location, :housing_location - - validates_presence_of :code - - def self.build(response) - attributes = response['establishment'] - attributes['housing_location'] = response['housing_location'].presence - new(attributes) - end - - def api_call_successful? - api_call_successful - end - end -end diff --git a/app/services/nomis/feature.rb b/app/services/nomis/feature.rb deleted file mode 100644 index c971af90..00000000 --- a/app/services/nomis/feature.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Nomis - class Feature - def self.slot_availability_enabled?(prison_name) - Nomis::Api.enabled? && config.nomis_staff_slot_availability_enabled && - config.staff_prisons_with_slot_availability.include?(prison_name) - end - - def self.config - Rails.configuration - end - end -end diff --git a/app/services/nomis/housing_location.rb b/app/services/nomis/housing_location.rb deleted file mode 100644 index 2978510e..00000000 --- a/app/services/nomis/housing_location.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Nomis - class HousingLocation - include MemoryModel - - attribute :description, :string - attribute :levels, :level_list - end -end diff --git a/app/services/nomis/housing_location/level.rb b/app/services/nomis/housing_location/level.rb deleted file mode 100644 index abde9e96..00000000 --- a/app/services/nomis/housing_location/level.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Nomis - class HousingLocation - class Level - include MemoryModel - - attribute :type, :string - attribute :value, :string - end - end -end diff --git a/app/services/nomis/prisoner/details.rb b/app/services/nomis/prisoner/details.rb deleted file mode 100644 index a85d48ef..00000000 --- a/app/services/nomis/prisoner/details.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Nomis - class Prisoner - class Details - include MemoryModel - - attribute :aliases - attribute :api_call_successful, :boolean, default: true - attribute :convicted, :boolean - attribute :cro_number, :string - attribute :csra - attribute :date_of_birth, :date - attribute :diet - attribute :ethnicity - attribute :gender - attribute :given_name, :string - attribute :iep_level - attribute :imprisonment_status - attribute :language - attribute :middle_names, :string - attribute :nationalities, :string - attribute :pnc_number, :string - attribute :religion - attribute :suffix - attribute :surname, :string - attribute :title, :string - attribute :security_category - - def valid? - api_call_successful - end - end - end -end diff --git a/app/services/nomis/prisoner_date_availability.rb b/app/services/nomis/prisoner_date_availability.rb deleted file mode 100644 index b79705b1..00000000 --- a/app/services/nomis/prisoner_date_availability.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Nomis - class PrisonerDateAvailability - include MemoryModel - - BOOKED_VISIT = 'booked_visit'.freeze - EXTERNAL_MOVEMENT = 'external_movement'.freeze - OUT_OF_VO = 'out_of_vo'.freeze - - attribute :date, :date - attribute :banned, :boolean - attribute :out_of_vo, :boolean - attribute :external_movement, :boolean - attribute :existing_visits, :availability_visit_list, default: [] - - def available?(requested_slot) - unavailable_reasons(requested_slot).empty? - end - - def unavailable_reasons(requested_slot) - reasons = [] - reasons << EXTERNAL_MOVEMENT if external_movement - reasons << OUT_OF_VO if out_of_vo - reasons << BOOKED_VISIT if booked_visit?(requested_slot) - reasons - end - - private - - def booked_visit?(requested_slot) - existing_visits.any? { |visit| visit.slot.overlaps?(requested_slot) } - end - end -end diff --git a/app/services/nomis/prisoner_detailed_availability.rb b/app/services/nomis/prisoner_detailed_availability.rb deleted file mode 100644 index 5845ac4d..00000000 --- a/app/services/nomis/prisoner_detailed_availability.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Nomis - class PrisonerDetailedAvailability - include MemoryModel - - attribute :dates, :prisoner_date_availability_list - - def self.build(attrs) - new_attrs = attrs.each_with_object(dates: []) do |(date, info), list| - availability = info.deep_dup - availability['date'] = date - list[:dates] << availability - end - - new(new_attrs) - end - - def available?(slot) - error_messages_for_slot(slot).empty? - end - - def error_messages_for_slot(slot) - availability_for(slot).unavailable_reasons(slot) - end - - private - - def availability_for(slot) - dates.find do |date_availability| - date_availability.date == slot.to_date - end - end - end -end diff --git a/app/services/nomis/restriction.rb b/app/services/nomis/restriction.rb deleted file mode 100644 index a85fb426..00000000 --- a/app/services/nomis/restriction.rb +++ /dev/null @@ -1,31 +0,0 @@ -module Nomis - class Restriction - include MemoryModel - - BANNED_CODE = 'BAN'.freeze - CLOSED_CODE = 'CLOSED'.freeze - - CLOSED_NAME = 'closed'.freeze - - attribute :type, :restriction_type - attribute :effective_date, :date - attribute :expiry_date, :date - attribute :comment_text, :string - - def banned? - type.code == BANNED_CODE - end - - def closed? - type.code == CLOSED_CODE - end - - def effective_at?(date) - date >= effective_date && (expiry_date.nil? || date <= expiry_date) - end - - def description - type.desc - end - end -end diff --git a/app/services/nomis/restriction/type.rb b/app/services/nomis/restriction/type.rb deleted file mode 100644 index 41915083..00000000 --- a/app/services/nomis/restriction/type.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Nomis - class Restriction - class Type < Code - end - end -end diff --git a/app/services/nomis/visit_order.rb b/app/services/nomis/visit_order.rb deleted file mode 100644 index 63007577..00000000 --- a/app/services/nomis/visit_order.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Nomis - class VisitOrder < Code - VO = 'VO'.freeze - PVO = 'PVO'.freeze - - attribute :number, :integer - end -end diff --git a/spec/fixtures/vcr_cassettes/client-auth.yml b/spec/fixtures/vcr_cassettes/client-auth.yml new file mode 100644 index 00000000..683185cc --- /dev/null +++ b/spec/fixtures/vcr_cassettes/client-auth.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/client-request-id.yml b/spec/fixtures/vcr_cassettes/client-request-id.yml new file mode 100644 index 00000000..54e348ac --- /dev/null +++ b/spec/fixtures/vcr_cassettes/client-request-id.yml @@ -0,0 +1,152 @@ +--- +http_interactions: +- request: + method: post + uri: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/oauth/token?grant_type=client_credentials + body: + encoding: UTF-8 + string: '' + headers: + User-Agent: + - Faraday v2.9.0 + Authorization: + - Basic cHZiLTI6clllWnBiUWRUS0M8eVp3QkJGN2JzJXg6OGk2TFhlRyY9QlJDRVZ6MHJ1VEhCelRKTndPUTJINzUrcVNo + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 403 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:53 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Access-Control-Request-Headers + - Access-Control-Request-Method + - Origin + Cache-Control: + - no-store + Pragma: + - no-cache + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - DENY + body: + encoding: UTF-8 + string: '{"error":"access_denied","error_description":"Unable to issue token + as request is not from ip within allowed list"}' + recorded_at: Tue, 07 May 2024 13:04:53 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - 'Bearer ' + X-Request-Id: + - uuid + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:58 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - Bearer error="invalid_token", error_description="Bearer token is malformed", + error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:58 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - 'Bearer ' + X-Request-Id: + - uuid + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - Bearer error="invalid_token", error_description="Bearer token is malformed", + error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:58 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/fetch_contact_list.yml b/spec/fixtures/vcr_cassettes/fetch_contact_list.yml new file mode 100644 index 00000000..bc756719 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/fetch_contact_list.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/contact_list + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/contact_list + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_active_prisoner.yml b/spec/fixtures/vcr_cassettes/lookup_active_prisoner.yml new file mode 100644 index 00000000..0e95f3b6 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_active_prisoner.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:01 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:01 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_active_prisoner_nomatch.yml b/spec/fixtures/vcr_cassettes/lookup_active_prisoner_nomatch.yml new file mode 100644 index 00000000..bc8c6fad --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_active_prisoner_nomatch.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=Z9999ZZ + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:01 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:01 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/lookup/active_offender?date_of_birth=1966-11-22&noms_id=Z9999ZZ + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:06 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:06 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_offender_details_invalid_noms_id.yml b/spec/fixtures/vcr_cassettes/lookup_offender_details_invalid_noms_id.yml new file mode 100644 index 00000000..46ace3ab --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_offender_details_invalid_noms_id.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/RUBBISH + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/RUBBISH + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_prisoner_details.yml b/spec/fixtures/vcr_cassettes/lookup_prisoner_details.yml new file mode 100644 index 00000000..188ffb66 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_prisoner_details.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:06 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:06 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G7244GR + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:06 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:06 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_prisoner_details_unknown_prisoner.yml b/spec/fixtures/vcr_cassettes/lookup_prisoner_details_unknown_prisoner.yml new file mode 100644 index 00000000..7fd0b30b --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_prisoner_details_unknown_prisoner.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G999999 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G999999 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_prisoner_location.yml b/spec/fixtures/vcr_cassettes/lookup_prisoner_location.yml new file mode 100644 index 00000000..3255557d --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_prisoner_location.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G7244GR/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G7244GR/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_bogus_prisoner.yml b/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_bogus_prisoner.yml new file mode 100644 index 00000000..833d2407 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_bogus_prisoner.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/BOGUS/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/BOGUS/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_unknown_prisoner.yml b/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_unknown_prisoner.yml new file mode 100644 index 00000000..52d04b7d --- /dev/null +++ b/spec/fixtures/vcr_cassettes/lookup_prisoner_location_for_unknown_prisoner.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G999999/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/G999999/location + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:04:59 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:04:59 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/nomis_oauth_jwks.yml b/spec/fixtures/vcr_cassettes/nomis_oauth_jwks.yml new file mode 100644 index 00000000..d2d9d8d4 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/nomis_oauth_jwks.yml @@ -0,0 +1,37 @@ +--- +http_interactions: +- request: + method: get + uri: https://sign-in-dev.hmpps.service.justice.gov.uk/auth/.well-known/jwks.json + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Faraday v2.9.0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:08 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Cache-Control: + - max-age=43200, public + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"hmpps-auth-dev-20230306","alg":"RS256","n":"kuHHlsEOWIrSz3zeU6CsovXzYRIk8FIIvewuV6Fm6Y3tlSs64CgrA0R9ZO9vqAO7H5N08GtLlDjuGGzP_fb8vQ1oSgGncllIrmvy-tgLHumKmUEJqU2tOnp3y6YDzRMesCdeoH1kOjjBtK-cur5tic8mSNKhyue5CuFgVm5N3Ol8cLaqkuZWTlZuWGiYXulfsSsn0RkpF3-NvXr95PTcg0ipcAhscM6rrUVkouWQ-nzwCjfB-Gu_u-OYR6lXiDxyf7YeaYJgv5HNnb1P4p_L36TNLECsOQHQFnorQmwHveyI8HcftsH7Oa6acN7n0zRpwhwSZGgXzViAry7LZnRJ4w"}]}' + recorded_at: Tue, 07 May 2024 13:05:08 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/prisoner_visiting_availability.yml b/spec/fixtures/vcr_cassettes/prisoner_visiting_availability.yml new file mode 100644 index 00000000..2d04922e --- /dev/null +++ b/spec/fixtures/vcr_cassettes/prisoner_visiting_availability.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/available_dates?end_date=2020-10-25&start_date=2020-10-15 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/available_dates?end_date=2020-10-25&start_date=2020-10-15 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/prisoner_visiting_availability_noavailability.yml b/spec/fixtures/vcr_cassettes/prisoner_visiting_availability_noavailability.yml new file mode 100644 index 00000000..f72a82d6 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/prisoner_visiting_availability_noavailability.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/available_dates?end_date=2020-10-18&start_date=2020-10-18 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/available_dates?end_date=2020-10-18&start_date=2020-10-18 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:00 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:00 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/prisoner_visiting_detailed_availability.yml b/spec/fixtures/vcr_cassettes/prisoner_visiting_detailed_availability.yml new file mode 100644 index 00000000..1d9e67db --- /dev/null +++ b/spec/fixtures/vcr_cassettes/prisoner_visiting_detailed_availability.yml @@ -0,0 +1,103 @@ +--- +http_interactions: +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/unavailability?dates=2020-10-15,2020-10-16,2020-10-17 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:07 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +- request: + method: get + uri: https://prison-api-dev.prison.service.justice.gov.uk/api/v1/offenders/1502035/visits/unavailability?dates=2020-10-15,2020-10-16,2020-10-17 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - excon/0.110.0 + Accept: + - application/json + Authorization: + - Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9pc3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIsImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4TLJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJmuUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri47gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg + X-Request-Id: + - '' + response: + status: + code: 401 + message: '' + headers: + Date: + - Tue, 07 May 2024 13:05:08 GMT + Content-Length: + - '0' + Connection: + - keep-alive + Vary: + - Origin, Access-Control-Request-Method, Access-Control-Request-Headers + Www-Authenticate: + - 'Bearer error="invalid_token", error_description="An error occurred while + attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, + or no matching key(s) found", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"' + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Pragma: + - no-cache + Expires: + - '0' + Strict-Transport-Security: + - max-age=15724800; includeSubDomains + X-Frame-Options: + - SAMEORIGIN + body: + encoding: ASCII-8BIT + string: '' + recorded_at: Tue, 07 May 2024 13:05:07 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/services/nomis/api_serialiser_spec.rb b/spec/services/nomis/api_serialiser_spec.rb new file mode 100644 index 00000000..93a48e27 --- /dev/null +++ b/spec/services/nomis/api_serialiser_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe Nomis::ApiSerialiser do + let!(:memory_model_class) do + Class.new do + include MemoryModel + attribute :foo, :string + end + end + + let(:payload) do + { foo: :bar, unknown_attribute: :boom } + end + + subject { model.new(payload) } + + it 'serialises a payload with unknown attributes', :expect_exception do + expect(described_class.new.serialise(memory_model_class, payload)).to have_attributes foo: 'bar' + end + + it 'raises an error in dev or tests mode' do + expect { + described_class.new.serialise(memory_model_class, payload) + }.to raise_error(Nomis::Error::UnhandledApiField) + end +end diff --git a/spec/services/nomis/api_slot_normaliser_spec.rb b/spec/services/nomis/api_slot_normaliser_spec.rb new file mode 100644 index 00000000..30d56ce4 --- /dev/null +++ b/spec/services/nomis/api_slot_normaliser_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +RSpec.describe Nomis::ApiSlotNormaliser do + subject { described_class.new(raw_slot).slot } + + describe "with a slot with correct times" do + let(:raw_slot) { "2017-02-01T14:00/14:30" } + + it 'does nothing' do + expect(subject.to_s).to eq(raw_slot) + end + end + + describe "with a slot with a begin_at out of sync" do + let(:raw_slot) { "2017-02-01T13:59/14:30" } + let(:correct_slot) { "2017-02-01T14:00/14:30" } + + it 'corrects the beginning time' do + expect(subject.to_s).to eq(correct_slot) + end + end + + describe "with a slot with a end_at out of sync" do + let(:raw_slot) { "2017-02-01T14:00/14:31" } + let(:correct_slot) { "2017-02-01T14:00/14:30" } + + it 'corrects the end time' do + expect(subject.to_s).to eq(correct_slot) + end + end + + describe "with a slot with both times out of sync" do + let(:raw_slot) { "2017-02-01T14:01/14:31" } + let(:correct_slot) { "2017-02-01T14:00/14:30" } + + it 'corrects the start and end times' do + expect(subject.to_s).to eq(correct_slot) + end + end +end diff --git a/spec/services/nomis/api_slot_spec.rb b/spec/services/nomis/api_slot_spec.rb new file mode 100644 index 00000000..6886e565 --- /dev/null +++ b/spec/services/nomis/api_slot_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe Nomis::ApiSlot do + subject do + described_class.new(time: unparsed_slot, + capacity: 4, + max_groups: 3, + groups_booked: 1, + adults_booked: 1) + end + + let(:unparsed_slot) { '2015-10-23T14:00/15:30' } + let(:parsed_slot) { ConcreteSlot.parse(unparsed_slot) } + + describe '#to_s' do + it { expect(subject.to_s).to eq(parsed_slot.to_s) } + end + + describe '#to_date' do + it { expect(subject.to_date).to eq(parsed_slot.to_date) } + end + + describe '<=>' do + let(:other) { described_class.new(time: '2016-10-23T14:00/15:30') } + + it 'is -1 when the other value is later in the future' do + expect(subject.<=>(other)).to eq(-1) + end + end +end diff --git a/spec/services/nomis/api_spec.rb b/spec/services/nomis/api_spec.rb new file mode 100644 index 00000000..6d90d8a5 --- /dev/null +++ b/spec/services/nomis/api_spec.rb @@ -0,0 +1,271 @@ +require 'rails_helper' + +RSpec.describe Nomis::Api do + subject { described_class.instance } + + # Ensure that we have a new instance to prevent other specs interfering + around do |ex| + Singleton.__init__(described_class) + ex.run + Singleton.__init__(described_class) + end + + it 'is implicitly enabled if the api host is configured' do + expect(Rails.configuration).to receive(:prison_api_host).and_return(nil) + expect(described_class.enabled?).to be false + + expect(Rails.configuration).to receive(:prison_api_host).and_return('http://example.com/') + expect(described_class.enabled?).to be true + end + + it 'fails if code attempts to use the client when disabled' do + expect(described_class).to receive(:enabled?).and_return(false) + expect { + described_class.instance + }.to raise_error(Nomis::Error::Disabled, 'Nomis API is disabled') + end + + describe 'lookup_active_prisoner', vcr: { cassette_name: :lookup_active_prisoner } do + let(:params) { + { + noms_id: 'G7244GR', + date_of_birth: Date.parse('1966-11-22') + } + } + + let(:prisoner) { subject.lookup_active_prisoner(**params) } + + it 'returns and prisoner if the data matches' do + expect(prisoner).to be_kind_of(Nomis::Prisoner) + expect(prisoner.nomis_offender_id).to eq(1_502_035) + expect(prisoner.noms_id).to eq('G7244GR') + end + + it 'returns NullPrisoner if the data does not match', vcr: { cassette_name: :lookup_active_prisoner_nomatch } do + params[:noms_id] = 'Z9999ZZ' + expect(prisoner).to be_instance_of(Nomis::NullPrisoner) + end + + it 'returns NullPrisoner if an ApiError is raised', :expect_exception do + allow_any_instance_of(Nomis::Client).to receive(:get).and_raise(Nomis::APIError) + expect(prisoner).to be_instance_of(Nomis::NullPrisoner) + expect(prisoner).not_to be_api_call_successful + end + + it 'logs the lookup result, api lookup time' do + prisoner + expect(PVB::Instrumentation.custom_log_items[:api]).to be > 1 + expect(PVB::Instrumentation.custom_log_items[:valid_prisoner_lookup]).to be true + end + + describe 'with no matching prisoner', vcr: { cassette_name: :lookup_active_prisoner_nomatch } do + before do + params[:noms_id] = 'Z9999ZZ' + end + + it 'returns nil if the data does not match' do + expect(prisoner).to be_instance_of(Nomis::NullPrisoner) + end + + it 'logs the prisoner was unsucessful' do + prisoner + expect(PVB::Instrumentation.custom_log_items[:valid_prisoner_lookup]).to be false + end + end + end + + describe '#lookup_prisoner_details' do + let(:prisoner_details) { described_class.instance.lookup_prisoner_details(noms_id:) } + + context 'when found', vcr: { cassette_name: :lookup_prisoner_details } do + let(:noms_id) { 'G7244GR' } + + it 'serialises the response into a prisonwe' do + expect(prisoner_details) + .to have_attributes( + given_name: "UDFSANAYE", + surname: "KURTEEN", + date_of_birth: Date.parse('1966-11-22'), + aliases: [], + gender: { 'code' => 'M', 'desc' => 'Male' }, + convicted: true, + imprisonment_status: { "code" => "SENT03", "desc" => "Adult Imprisonment Without Option CJA03" }, + iep_level: { "code" => "ENH", "desc" => "Enhanced" } + ) + end + + it 'instruments the request' do + prisoner_details + expect(PVB::Instrumentation.custom_log_items[:valid_prisoner_details_lookup]).to be true + end + end + + context 'when an unknown prisoner', :expect_exception, vcr: { cassette_name: :lookup_prisoner_details_unknown_prisoner } do + let(:noms_id) { 'G999999' } + + it { expect { prisoner_details }.to raise_error(Nomis::APIError) } + end + + context 'when given an invalid nomis id', :expect_exception, vcr: { cassette_name: :lookup_offender_details_invalid_noms_id } do + let(:noms_id) { 'RUBBISH' } + + it { expect { prisoner_details }.to raise_error(Nomis::APIError) } + end + end + + describe '#lookup_prisoner_location' do + let(:establishment) { subject.lookup_prisoner_location(noms_id:) } + + context 'when found', vcr: { cassette_name: :lookup_prisoner_location } do + let(:noms_id) { 'G7244GR' } + + it 'returns a Location' do + expect(establishment).to be_valid + expect(establishment.code).to eq 'LEI' + end + + it 'has the internal location' do + expect(establishment).to have_attributes(housing_location: instance_of(Nomis::HousingLocation)) + expect(establishment.housing_location.description).to eq 'LEI-F-3-005' + end + end + + context 'with an unknown offender', :expect_exception, vcr: { cassette_name: :lookup_prisoner_location_for_unknown_prisoner } do + let(:noms_id) { 'G999999' } + + it { expect { establishment }.to raise_error(Nomis::APIError) } + end + + context 'with an invalid nomis_id', :expect_exception, vcr: { cassette_name: :lookup_prisoner_location_for_bogus_prisoner } do + let(:noms_id) { 'BOGUS' } + + it { expect { establishment }.to raise_error(Nomis::APIError) } + end + end + + describe 'prisoner_visiting_availability', vcr: { cassette_name: :prisoner_visiting_availability } do + let(:params) { + { + offender_id: 1_502_035, + start_date: '2020-10-15', + end_date: '2020-10-25' + } + } + + context 'when the prisoner has availability' do + subject { super().prisoner_visiting_availability(**params) } + + it 'returns availability info containing a list of available dates' do + expect(subject).to be_kind_of(Nomis::PrisonerAvailability) + expect(subject.dates.first).to eq(Date.parse('2020-10-15')) + end + + it 'logs the number of available dates' do + expect(subject.dates.count).to eq(PVB::Instrumentation.custom_log_items[:prisoner_visiting_availability]) + end + end + + context 'when the prisoner has no availability' do + # This spec has to have a hard coded date as an offender MUST be unavailable on a specific date in order for this to + # pass. Unfortunately we are unable to use 'travel_to' and go to the past as the JWT token skew is too large. If this + # test needs updating a new date will need to be added and updated as part of the VCR being recorded + let(:params) { + { + offender_id: 1_502_035, + start_date: Date.parse('2020-10-18'), + end_date: Date.parse('2020-10-18') + } + } + + subject { super().prisoner_visiting_availability(**params) } + + it 'returns empty list of available dates if there is no availability', vcr: { cassette_name: :prisoner_visiting_availability_noavailability } do + expect(subject).to be_kind_of(Nomis::PrisonerAvailability) + expect(subject.dates).to be_empty + end + end + end + + describe 'prisoner_visiting_detailed_availability', vcr: { cassette_name: :prisoner_visiting_detailed_availability } do + let(:slot1) { ConcreteSlot.new(2020, 10, 15, 10, 0, 11, 0) } + let(:slot2) { ConcreteSlot.new(2020, 10, 16, 10, 0, 11, 0) } + let(:slot3) { ConcreteSlot.new(2020, 10, 17, 10, 0, 11, 0) } + let(:params) do + { + offender_id: 1_502_035, + slots: [slot1, slot2, slot3] + } + end + + subject { super().prisoner_visiting_detailed_availability(**params) } + + it 'returns availability info containing a list of available dates' do + expect(subject).to be_kind_of(Nomis::PrisonerDetailedAvailability) + expect(subject.dates.map(&:date)) + .to contain_exactly(slot1.to_date, slot2.to_date, slot3.to_date) + end + + it 'logs the number of available slots' do + subject + expect(PVB::Instrumentation.custom_log_items[:prisoner_visiting_availability]).to eq(3) + end + end + + describe 'fetch_bookable_slots', vcr: { cassette_name: :fetch_bookable_slots } do + # There have been issues with the visit slots for Leeds in T3 and therefore we have switched to use The Verne + # for this spec + let(:params) { + { + prison: instance_double(Prison, nomis_id: 'VEI'), + start_date: '2020-10-14', + end_date: '2020-10-24' + } + } + + subject { super().fetch_bookable_slots(**params) } + + it 'returns an array of slots' do + expect(subject.first.time.iso8601).to eq("2020-10-14T14:00/16:00") + end + + it 'logs the number of available slots' do + expect(subject.count).to eq(PVB::Instrumentation.custom_log_items[:slot_visiting_availability]) + end + end + + describe 'fetch_contact_list', vcr: { cassette_name: :fetch_contact_list } do + let(:params) do + { + offender_id: 1_502_035 + } + end + + let(:first_contact) do + Nomis::Contact.new( + id: 2_996_406, + given_name: 'AELAREET', + surname: 'ANTOINETTE', + date_of_birth: '1990-09-22', + gender: { code: "M", desc: "Male" }, + active: true, + approved_visitor: true, + relationship_type: { code: "SON", desc: "Son" }, + contact_type: { + code: "S", + desc: "Social/ Family" + }, + restrictions: [] + ) + end + + subject { super().fetch_contact_list(**params) } + + it 'returns an array of contacts' do + expect(subject).to have_exactly(27).items + end + + it 'parses the contacts' do + expect(subject.map(&:id)).to include(first_contact.id) + end + end +end diff --git a/spec/services/nomis/client_spec.rb b/spec/services/nomis/client_spec.rb new file mode 100644 index 00000000..831e0796 --- /dev/null +++ b/spec/services/nomis/client_spec.rb @@ -0,0 +1,161 @@ +require 'rails_helper' + +RSpec.describe Nomis::Client do + subject { described_class.new(api_host) } + + let(:api_host) { Rails.configuration.prison_api_host } + + let(:path) { 'v1/lookup/active_offender' } + let(:params) { + { + noms_id: 'G7244GR', + date_of_birth: Date.parse('1966-11-22') + } + } + + describe 'with a valid request', vcr: { cassette_name: 'client-request-id' } do + it 'sets the X-Request-Id header if a request_id is present' do + RequestStore.store[:request_id] = 'uuid' + subject.get(path, params) + expect(WebMock).to have_requested(:get, /\w/) + .with(headers: { 'X-Request-Id' => 'uuid' }) + end + end + + context 'when there is an http status error' do + let(:error) do + Excon::Error::HTTPStatus.new('error', + double('request'), + double('response', status: 422, body: '')) + end + + before do + WebMock.stub_request(:get, /\w/).to_raise(error) + end + + it 'raises an APIError', :expect_exception do + expect { subject.get(path, params) } + .to raise_error(Nomis::APIError, 'Unexpected status 422 calling GET /api/v1/lookup/active_offender: (invalid-JSON) ') + end + + it 'sends the error to sentry' do + expect(PVB::ExceptionHandler).to receive(:capture_exception).with(error, fingerprint: %w[nomis excon]) + + expect { subject.get(path, params) }.to raise_error(Nomis::APIError) + end + end + + context 'when there is a timeout' do + before do + WebMock.stub_request(:get, /\w/).to_timeout + end + + it 'raises an Nomis::TimeoutError if a timeout occurs', :expect_exception do + expect { + subject.get(path, params) + }.to raise_error(Nomis::APIError) + end + end + + context 'when there is an unexpected exception' do + let(:error) do + Excon::Errors::SocketError.new(StandardError.new('Socket error')) + end + + before do + WebMock.stub_request(:get, /\w/).to_raise(error) + end + + it 'raises an APIError if an unexpected exception is raised containing request information', :expect_exception do + expect { + subject.get(path, params) + }.to raise_error(Nomis::APIError) + end + end + + describe 'with an error' do + let(:error) do + Excon::Error::HTTPStatus.new('error', + double('request'), + double('response', status: 422, body: '')) + end + + before do + WebMock.stub_request(:get, /\w/).to_raise(error) + end + + it 'raises an APIError if an unexpected exception is raised containing request information', :expect_exception do + expect { + subject.get(path, params) + }.to raise_error(Nomis::APIError, 'Unexpected status 422 calling GET /api/v1/lookup/active_offender: (invalid-JSON) ') + end + + it 'sends the error to sentry' do + expect(PVB::ExceptionHandler).to receive(:capture_exception).with(error, fingerprint: %w[nomis excon]) + + expect { subject.get(path, params) }.to raise_error(Nomis::APIError) + end + + it 'increments the api error count', :expect_exception do + expect { + subject.get(path, params) + }.to raise_error(Nomis::APIError) + .and change { PVB::Instrumentation.custom_log_items[:api_request_count] }.from(nil).to(1) + end + end + + describe 'with auth configured' do + let(:access_token) do + 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRwcy1jbGllbnQta2V5In0.eyJzdWIiOiJ0' \ + 'ZXN0IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInNjb3BlIjpbInJlYWQiLCJ3cml0' \ + 'ZSJdLCJhdXRoX3NvdXJjZSI6Im5vbmUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjkwOTAvYXV0aC9p' \ + 'c3N1ZXIiLCJleHAiOjE2Nzg0NjY3MTEsImp0aSI6IkRIbnY3ZElCSFdjdmh6akdlTFotZFlGSndGMCIs' \ + 'ImNsaWVudF9pZCI6InRlc3QifQ.QLYRxudeQeh_54fJmMNevmHrt2d6hci6qqbqskPt41hvFWCLOrA4T' \ + 'LJSkRsu-u3l1grZKpWJWKUlI0v51BnjnzkJ8oJBUQ738qILpN_lZixxxP1QB2sqL-tO2NgXW3H2-HPvJ' \ + 'muUWABr5WBbzEbCvy9xMQhlMGN3BAi-EbbOmAjzP53194ggcojHz2tlAfav6Z8qSc1BKeSrMRVq6cA42' \ + 'xLER61URCSAYfjRa_wTlFALi-K7CKdsD2T8zsO2H8kBxDx5nJN_5beMPCFkKLN66NAEtiAfEgHZE9ri4' \ + '7gWVC1gPrm6-S6CoIGu54KNQ6hF8rsntFeFvPr1ff8WrRgOtg' + end + + let(:nomis_oauth_host) { 'http://localhost:9090' } + let(:nomis_oauth_client_id) { 'test' } + let(:nomis_oauth_client_secret) { '6+9tp>hSA.Kq7Rjtab.6V9P-lW*TZIW:2nj8>u&2F&>snY5G9v' } + + before do + Nomis::Oauth::TokenService.host = nomis_oauth_host + Nomis::Oauth::Client.nomis_oauth_client_id = nomis_oauth_client_id + Nomis::Oauth::Client.nomis_oauth_client_secret = nomis_oauth_client_secret + + stub_request(:post, "#{nomis_oauth_host}/auth/oauth/token?grant_type=client_credentials") + .to_return( + body: { + access_token:, + token_type: 'bearer', + expires_in: 3599, + scope: 'read write', + sub: 'test', + auth_source: 'none', + jti: 'DHnv7dIBHWcvhzjGeLZ-dYFJwF0', + iss: 'http://localhost:9090/auth/issuer' + }.to_json + ) + end + + after do + Nomis::Oauth::TokenService.host = Rails.configuration.nomis_oauth_host + Nomis::Oauth::Client.nomis_oauth_client_id = Rails.configuration.nomis_oauth_client_id + Nomis::Oauth::Client.nomis_oauth_client_secret = Rails.configuration.nomis_oauth_client_secret + end + + it 'sends an Authorization header containing a JWT token', vcr: { cassette_name: 'client-auth' } do + subject.get(path, params) + expect(WebMock).to have_requested(:get, /\w/) + .with { |req| + auth_type, token = req.headers["Authorization"].split(' ') + next unless auth_type == 'Bearer' + + expect(token).to eq(access_token) + } + end + end +end diff --git a/spec/services/nomis/null_prisoner_spec.rb b/spec/services/nomis/null_prisoner_spec.rb new file mode 100644 index 00000000..00762bbf --- /dev/null +++ b/spec/services/nomis/null_prisoner_spec.rb @@ -0,0 +1,6 @@ +require "rails_helper" + +RSpec.describe Nomis::NullPrisoner do + it { expect(subject.iep_level).to eq(nil) } + it { expect(subject.imprisonment_status).to eq(nil) } +end diff --git a/spec/services/nomis/oauth/client_spec.rb b/spec/services/nomis/oauth/client_spec.rb new file mode 100644 index 00000000..c882e47a --- /dev/null +++ b/spec/services/nomis/oauth/client_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' +require 'base64' + +RSpec.describe Nomis::Oauth::Client do + describe '#post' do + let(:auth_header) do + 'Basic bXlfY2xpZW50X2lkOmFfdmFsdWVfbGlrZV8+Pj5fdGhhdF9iYXNlNjRfZW5jb2Rlc193aXRoX3BsdXNfb3Jfc2xhc2g=' + end + + describe 'with a valid request' do + let(:client_id) { 'my_client_id' } + let(:client_secret) { 'a_value_like_>>>_that_base64_encodes_with_plus_or_slash' } + + before do + described_class.nomis_oauth_client_id = client_id + described_class.nomis_oauth_client_secret = client_secret + end + + after do + described_class.nomis_oauth_client_id = Rails.configuration.nomis_oauth_host + described_class.nomis_oauth_client_secret = Rails.configuration.nomis_oauth_client_secret + end + + it 'sets the Authorization header' do + WebMock.stub_request(:post, /\w/).to_return(body: '{}') + + api_host = Rails.configuration.nomis_oauth_host + route = '/auth/oauth/token?grant_type=client_credentials' + client = described_class.new(api_host) + + client.post(route) + + expect(WebMock).to have_requested(:post, /\w/) + .with( + headers: { + Authorization: auth_header + } + ) + end + end + end + + describe '#get' do + it 'does not set the Authorization header' do + WebMock.stub_request(:get, /\w/).to_return(body: '{}') + + api_host = Rails.configuration.nomis_oauth_host + route = '/auth/.well-known/jwks.json' + client = described_class.new(api_host) + + client.get(route) + + expect(WebMock).to have_requested(:get, /\w\/auth\/.well-known\/jwks.json/) + .with { |request| expect(request.headers).not_to include('Authorization') } + end + end +end diff --git a/spec/services/nomis/oauth/jwks_service_spec.rb b/spec/services/nomis/oauth/jwks_service_spec.rb new file mode 100644 index 00000000..2a5bec37 --- /dev/null +++ b/spec/services/nomis/oauth/jwks_service_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe Nomis::Oauth::JwksService do + subject { described_class.instance } + + describe '#fetch_keys' do + it 'returns jwks keys as JSON array', vcr: { cassette_name: 'nomis_oauth_jwks' } do + expect(subject.fetch_keys).to eq( + "keys" => [{ + "kty" => "RSA", + "e" => "ABQ", + "use" => "sig", + "kid" => "user-kid", + "alg" => "RS256", + "n" => "ZII/AvQAeYSKRaa77rvYP2U+8XrP4Tk0nN0gRE2i+pBqT1wNh1f3gDvdRAa5QZzQc9xY7tKD2WiTYaITjlC+hXObvQaYfsEZtZG+zd5pTtcf96ck0j44c9bdwQ23T9nKgWTMwA==" + }] + ) + end + end +end diff --git a/spec/services/nomis/oauth/token_service_spec.rb b/spec/services/nomis/oauth/token_service_spec.rb new file mode 100644 index 00000000..c6dd7a17 --- /dev/null +++ b/spec/services/nomis/oauth/token_service_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe Nomis::Oauth::TokenService do + # Ensure that we have a new instance to prevent other specs interfering + around do |ex| + Singleton.__init__(described_class) + ex.run + Singleton.__init__(described_class) + end + + it 'fetches a new auth token if it is expired' do + unexpired_token = Nomis::Oauth::Token.new(access_token: generate_jwt_token) + expired_encoded_token = generate_jwt_token(exp: Time.current.to_i - 3600) + expired_token = Nomis::Oauth::Token.new(access_token: expired_encoded_token) + + expect_any_instance_of(described_class) + .to receive(:fetch_token) + .and_return(expired_token, unexpired_token) + + token_service = described_class.instance + + expect(token_service.valid_token).to eq(unexpired_token) + end +end diff --git a/spec/services/nomis/prisoner_spec.rb b/spec/services/nomis/prisoner_spec.rb new file mode 100644 index 00000000..0dec2934 --- /dev/null +++ b/spec/services/nomis/prisoner_spec.rb @@ -0,0 +1,77 @@ +require "rails_helper" + +RSpec.describe Nomis::Prisoner, type: :model do + let(:noms_id) { 'A1459AE' } + + it { is_expected.to validate_presence_of :id } + it { is_expected.to validate_presence_of :noms_id } + + subject { described_class.new(noms_id:) } + + context 'with an unormalised noms_id' do + let(:noms_id) { 'A1234bc ' } + + it 'normalises the noms_id' do + expect(subject.noms_id).to eq('A1234BC') + end + end + + describe '#iep_level' do + context 'with a successful API call' do + describe 'with an iep level' do + before do + mock_nomis_with( + :lookup_prisoner_details, + Nomis::Prisoner::Details.new( + iep_level: { 'code' => 'STD', 'desc' => 'Standard' } + ) + ) + end + + it { expect(subject.iep_level).to eq('Standard') } + end + + describe 'when the prisoner does not have an iep_level' do + before do + mock_nomis_with( + :lookup_prisoner_details, + Nomis::Prisoner::Details.new(iep_level: nil) + ) + end + + it { expect(subject.iep_level).to be nil } + end + end + + context 'with a unsuccessful API call' do + before do + simulate_api_error_for(:lookup_prisoner_details) + end + + it { expect(subject.iep_level).to be nil } + end + end + + describe '#imprisonment_status' do + context 'with a successful API call' do + before do + mock_nomis_with( + :lookup_prisoner_details, + Nomis::Prisoner::Details.new( + imprisonment_status: { 'code' => 'RX', 'desc' => 'Remanded to Magistrates Court' } + ) + ) + end + + it { expect(subject.imprisonment_status).to eq('Remanded to Magistrates Court') } + end + + context 'with a unsuccessful API call' do + before do + simulate_api_error_for(:lookup_prisoner_details) + end + + it { expect(subject.imprisonment_status).to be nil } + end + end +end