From d321b169106107993dfe9266e49bb3d77c205468 Mon Sep 17 00:00:00 2001 From: Dillo Raju Date: Wed, 15 Sep 2021 11:25:17 -0400 Subject: [PATCH] 7853 Lorota Integration (#7853) --- .../check_in/application_controller.rb | 13 +- .../v1/patient_check_ins_controller.rb | 25 ++- .../check_in/v1/sessions_controller.rb | 48 +++++ .../app/models/check_in/check_in_with_auth.rb | 30 ++++ .../check_in/app/services/v1/chip/service.rb | 4 +- .../services/v1/lorota/basic_claims_token.rb | 52 ++++++ .../services/v1/lorota/basic_redis_handler.rb | 43 +++++ .../app/services/v1/lorota/basic_service.rb | 52 ++++++ .../app/services/v1/lorota/basic_session.rb | 29 +++ .../app/services/v1/lorota/basic_token.rb | 32 ++++ .../app/services/v1/lorota/claims_token.rb | 18 ++ .../app/services/v1/lorota/redis_handler.rb | 11 ++ .../app/services/v1/lorota/request.rb | 61 +++++++ .../app/services/v1/lorota/response.rb | 39 +++++ .../app/services/v1/lorota/service.rb | 19 ++ .../app/services/v1/lorota/session.rb | 13 ++ .../check_in/app/services/v1/lorota/token.rb | 28 +++ modules/check_in/config/routes.rb | 2 +- modules/check_in/lib/check_in/engine.rb | 3 + .../check_in/check_in_with_auth_spec.rb | 80 +++++++++ .../v1/patient_check_ins_request_spec.rb | 119 ++++++++++++- .../spec/request/v1/sessions_request_spec.rb | 165 ++++++++++++++++++ .../spec/services/v1/chip/service_spec.rb | 13 ++ .../v1/lorota/basic_redis_handler_spec.rb | 63 +++++++ .../services/v1/lorota/basic_service_spec.rb | 100 +++++++++++ .../services/v1/lorota/basic_session_spec.rb | 68 ++++++++ .../services/v1/lorota/basic_token_spec.rb | 58 ++++++ .../spec/services/v1/lorota/request_spec.rb | 86 +++++++++ .../spec/services/v1/lorota/response_spec.rb | 74 ++++++++ .../spec/services/v1/lorota/token_spec.rb | 64 +++++++ 30 files changed, 1402 insertions(+), 10 deletions(-) create mode 100644 modules/check_in/app/controllers/check_in/v1/sessions_controller.rb create mode 100644 modules/check_in/app/models/check_in/check_in_with_auth.rb create mode 100644 modules/check_in/app/services/v1/lorota/basic_claims_token.rb create mode 100644 modules/check_in/app/services/v1/lorota/basic_redis_handler.rb create mode 100644 modules/check_in/app/services/v1/lorota/basic_service.rb create mode 100644 modules/check_in/app/services/v1/lorota/basic_session.rb create mode 100644 modules/check_in/app/services/v1/lorota/basic_token.rb create mode 100644 modules/check_in/app/services/v1/lorota/claims_token.rb create mode 100644 modules/check_in/app/services/v1/lorota/redis_handler.rb create mode 100644 modules/check_in/app/services/v1/lorota/request.rb create mode 100644 modules/check_in/app/services/v1/lorota/response.rb create mode 100644 modules/check_in/app/services/v1/lorota/service.rb create mode 100644 modules/check_in/app/services/v1/lorota/session.rb create mode 100644 modules/check_in/app/services/v1/lorota/token.rb create mode 100644 modules/check_in/spec/models/check_in/check_in_with_auth_spec.rb create mode 100644 modules/check_in/spec/request/v1/sessions_request_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/basic_redis_handler_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/basic_service_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/basic_session_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/basic_token_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/request_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/response_spec.rb create mode 100644 modules/check_in/spec/services/v1/lorota/token_spec.rb diff --git a/modules/check_in/app/controllers/check_in/application_controller.rb b/modules/check_in/app/controllers/check_in/application_controller.rb index d7da887cac1..71989c74f95 100644 --- a/modules/check_in/app/controllers/check_in/application_controller.rb +++ b/modules/check_in/app/controllers/check_in/application_controller.rb @@ -2,7 +2,12 @@ module CheckIn class ApplicationController < ::ApplicationController - before_action :authorize + include ActionController::Cookies + include ActionController::RequestForgeryProtection + + protect_from_forgery with: :exception + + before_action :authorize, :set_csrf_cookie skip_before_action :authenticate skip_before_action :verify_authenticity_token @@ -11,5 +16,11 @@ class ApplicationController < ::ApplicationController def authorize routing_error unless Flipper.enabled?('check_in_experience_enabled', params[:cookie_id]) end + + private + + def set_csrf_cookie + cookies['CSRF-TOKEN'] = form_authenticity_token + end end end diff --git a/modules/check_in/app/controllers/check_in/v1/patient_check_ins_controller.rb b/modules/check_in/app/controllers/check_in/v1/patient_check_ins_controller.rb index 81a697e53ec..700f5ec88a0 100644 --- a/modules/check_in/app/controllers/check_in/v1/patient_check_ins_controller.rb +++ b/modules/check_in/app/controllers/check_in/v1/patient_check_ins_controller.rb @@ -3,19 +3,34 @@ module CheckIn module V1 class PatientCheckInsController < CheckIn::ApplicationController - def show; end + def show + check_in = CheckIn::PatientCheckIn.build(uuid: params[:id]) + resp = + if session[:jwt].present? + ::V1::Lorota::Service.build(check_in: check_in).get_check_in + else + ::V1::Lorota::BasicService.build(check_in: check_in).get_check_in + end + + render json: resp + end def create - check_in = CheckIn::PatientCheckIn.build(uuid: patient_check_in_params[:id]) - data = ::V1::Chip::Service.build(check_in).create_check_in + check_in = CheckIn::PatientCheckIn.build(uuid: patient_check_in_params[:uuid]) + resp = + if session[:jwt] + ::V1::Chip::Service.build(check_in).create_check_in + else + { data: { error: true, message: 'Check-in failed' }, status: 403 } + end - render json: data + render json: resp end private def patient_check_in_params - params.require(:patient_check_ins).permit(:id) + params.require(:patient_check_ins).permit(:uuid) end def authorize diff --git a/modules/check_in/app/controllers/check_in/v1/sessions_controller.rb b/modules/check_in/app/controllers/check_in/v1/sessions_controller.rb new file mode 100644 index 00000000000..84d43954478 --- /dev/null +++ b/modules/check_in/app/controllers/check_in/v1/sessions_controller.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module CheckIn + module V1 + class SessionsController < CheckIn::ApplicationController + def show + check_in = CheckIn::PatientCheckIn.build(uuid: params[:id]) + resp = + if session[:jwt].present? + { data: + { permissions: 'read.full', uuid: check_in.uuid, status: 'success', jwt: session[:jwt] }, + status: 200 } + else + ::V1::Lorota::BasicService.build(check_in: check_in).get_or_create_token + end + + render json: resp + end + + def create + check_in = CheckIn::CheckInWithAuth.build(data: session_params) + resp = + if session[:jwt].present? + { data: + { permissions: 'read.full', uuid: check_in.uuid, status: 'success', jwt: session[:jwt] }, + status: 200 } + else + data = ::V1::Lorota::Service.build(check_in: check_in).get_or_create_token + + session[:jwt] = data.dig(:data, :jwt) + data + end + + render json: resp + end + + private + + def session_params + params.require(:session).permit(:uuid, :last4, :last_name) + end + + def authorize + routing_error unless Flipper.enabled?('check_in_experience_low_authentication_enabled') + end + end + end +end diff --git a/modules/check_in/app/models/check_in/check_in_with_auth.rb b/modules/check_in/app/models/check_in/check_in_with_auth.rb new file mode 100644 index 00000000000..fd6786643b8 --- /dev/null +++ b/modules/check_in/app/models/check_in/check_in_with_auth.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module CheckIn + class CheckInWithAuth < PatientCheckIn + LAST_FOUR_REGEX = /^[0-9]{4}$/.freeze + LAST_NAME_REGEX = /^.{1,600}$/.freeze + + attr_reader :last4, :last_name + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @uuid = opts.dig(:data, :uuid) + @last4 = opts.dig(:data, :last4) + @last_name = opts.dig(:data, :last_name) + end + + def valid? + UUID_REGEX.match?(uuid) && LAST_FOUR_REGEX.match?(last4) && LAST_NAME_REGEX.match?(last_name) + end + + def client_error + body = { error: true, message: 'Invalid uuid, last4 or last name!' } + + Faraday::Response.new(body: body, status: 400) + end + end +end diff --git a/modules/check_in/app/services/v1/chip/service.rb b/modules/check_in/app/services/v1/chip/service.rb index 18df09082c1..01380c524f3 100644 --- a/modules/check_in/app/services/v1/chip/service.rb +++ b/modules/check_in/app/services/v1/chip/service.rb @@ -15,15 +15,15 @@ def self.build(check_in) end def initialize(check_in) + @settings = Settings.check_in.chip_api_v1 @check_in = check_in @request = Request.build @response = Response @session = Session.build - @settings = Settings.check_in.chip_api_v1 end def create_check_in - return handle_response(client_error) unless valid? + return response.build(response: client_error).handle unless valid? token = session.retrieve resp = request.post(path: "/#{base_path}/actions/check-in/#{uuid}", access_token: token) diff --git a/modules/check_in/app/services/v1/lorota/basic_claims_token.rb b/modules/check_in/app/services/v1/lorota/basic_claims_token.rb new file mode 100644 index 00000000000..27b782144c5 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/basic_claims_token.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class BasicClaimsToken + SIGNING_ALGORITHM = 'RS256' + + extend Forwardable + + attr_reader :expiration, :settings, :check_in + + def_delegators :settings, :key_path + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + @expiration = 1440 + end + + def sign_assertion + JWT.encode(claims, rsa_key, SIGNING_ALGORITHM) + end + + def claims + { + aud: 'lorota', + iss: 'vets-api', + sub: check_in.uuid, + scopes: ['read.basic'], + iat: issued_at_time, + exp: expires_at_time + } + end + + def rsa_key + @rsa_key ||= OpenSSL::PKey::RSA.new(File.read(key_path)) + end + + def issued_at_time + @issued_at_time ||= Time.zone.now.to_i + end + + def expires_at_time + @expires_at_time ||= expiration.minutes.from_now.to_i + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/basic_redis_handler.rb b/modules/check_in/app/services/v1/lorota/basic_redis_handler.rb new file mode 100644 index 00000000000..d6a122ba8eb --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/basic_redis_handler.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class BasicRedisHandler + extend Forwardable + + attr_reader :check_in, :settings + attr_accessor :token + + def_delegators :settings, :redis_session_prefix + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + end + + def get + Rails.cache.read( + build_session_id_prefix, + namespace: 'check-in-lorota-v1-cache' + ) + end + + def save + Rails.cache.write( + build_session_id_prefix, + token.access_token, + namespace: 'check-in-lorota-v1-cache', + expires_in: 1440.minutes + ) + end + + def build_session_id_prefix + @build_session_id_prefix ||= "#{redis_session_prefix}_#{check_in.uuid}_read.basic" + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/basic_service.rb b/modules/check_in/app/services/v1/lorota/basic_service.rb new file mode 100644 index 00000000000..b6559257fa0 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/basic_service.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class BasicService + extend Forwardable + + attr_reader :check_in, :response, :session, :settings, :request + + def_delegators :check_in, :client_error, :valid? + def_delegators :settings, :base_path + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + @session = BasicSession.build(check_in: check_in) + @request = Request.build(token: session.from_redis) + @response = Response + end + + def get_or_create_token + data = session.from_redis || session.from_lorota + + format_data(data) + end + + def get_check_in + token = session.from_redis + + if token.present? + data = request.get("/#{base_path}/data/#{check_in.uuid}") + + Oj.load(data.body) + end + end + + def format_data(data) + body = { permissions: permissions, uuid: check_in.uuid, status: 'success', jwt: data } + + response.build(response: Faraday::Response.new(body: body, status: 200)).handle + end + + def permissions + 'read.basic' + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/basic_session.rb b/modules/check_in/app/services/v1/lorota/basic_session.rb new file mode 100644 index 00000000000..d65c681069a --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/basic_session.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class BasicSession + attr_reader :check_in, :token, :redis_handler + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @check_in = opts[:check_in] + @token = BasicToken.build(check_in: check_in) + @redis_handler = BasicRedisHandler.build(check_in: check_in) + end + + def from_redis + redis_handler.get + end + + def from_lorota + redis_handler.token = token.fetch + redis_handler.save + redis_handler.get + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/basic_token.rb b/modules/check_in/app/services/v1/lorota/basic_token.rb new file mode 100644 index 00000000000..eb481e13004 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/basic_token.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class BasicToken + extend Forwardable + + attr_reader :request, :claims_token, :check_in, :settings + attr_accessor :access_token + + def_delegators :settings, :base_path + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + @claims_token = BasicClaimsToken.build(check_in: check_in).sign_assertion + @request = Request.build(claims_token: claims_token) + end + + def fetch + resp = request.post("/#{base_path}/token", {}) + + self.access_token = Oj.load(resp.body)&.fetch('token') + self + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/claims_token.rb b/modules/check_in/app/services/v1/lorota/claims_token.rb new file mode 100644 index 00000000000..54793d063f0 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/claims_token.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class ClaimsToken < BasicClaimsToken + def claims + { + aud: 'lorota', + iss: 'vets-api', + sub: check_in.uuid, + scopes: ['read.full'], + iat: issued_at_time, + exp: expires_at_time + } + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/redis_handler.rb b/modules/check_in/app/services/v1/lorota/redis_handler.rb new file mode 100644 index 00000000000..95b0f30414f --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/redis_handler.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class RedisHandler < BasicRedisHandler + def build_session_id_prefix + @build_session_id_prefix ||= "#{redis_session_prefix}_#{check_in.uuid}_read.full" + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/request.rb b/modules/check_in/app/services/v1/lorota/request.rb new file mode 100644 index 00000000000..33cfbfd7d5c --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/request.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class Request + extend Forwardable + include Common::Client::Concerns::Monitoring + + STATSD_KEY_PREFIX = 'api.check_in.v1.lorota_api.request' + + attr_reader :claims_token, :settings, :token + attr_accessor :headers + + def_delegators :settings, :api_key, :api_id, :service_name, :url + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @claims_token = opts[:claims_token] + @token = opts[:token] + @headers = default_headers + end + + def get(path) + with_monitoring do + connection.get(path) do |req| + req.headers = default_headers.merge('Authorization' => "Bearer #{token}") + end + end + end + + def post(path, params) + with_monitoring do + connection.post(path) do |req| + req.headers = default_headers.merge('x-lorota-claims' => claims_token) + req.body = params.to_json + end + end + end + + def connection + Faraday.new(url: url) do |conn| + conn.use :breakers + conn.response :raise_error, error_prefix: service_name + conn.adapter Faraday.default_adapter + end + end + + def default_headers + { + 'Content-Type' => 'application/json', + 'x-api-key' => api_key, + 'x-apigw-api-id' => api_id + } + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/response.rb b/modules/check_in/app/services/v1/lorota/response.rb new file mode 100644 index 00000000000..832902b8e05 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/response.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class Response + attr_reader :body, :status + + def self.build(opts = {}) + new(opts) + end + + def initialize(opts) + @body = opts[:response].body || [] + @status = opts[:response].status + end + + def handle + value = begin + Oj.load(body) + rescue + body + end + + case status + when 200, 400 + { data: value, status: status } + when 401 + { data: { error: true, message: 'Unauthorized' }, status: status } + when 404 + { data: { error: true, message: 'We could not find that resource' }, status: status } + when 403 + { data: { error: true, message: 'Forbidden' }, status: status } + else + { data: { error: true, message: 'Something went wrong' }, status: status } + end + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/service.rb b/modules/check_in/app/services/v1/lorota/service.rb new file mode 100644 index 00000000000..b046b4dd849 --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/service.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class Service < BasicService + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + @session = Session.build(check_in: check_in) + @request = Request.build(token: session.from_redis) + @response = Response + end + + def permissions + 'read.full' + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/session.rb b/modules/check_in/app/services/v1/lorota/session.rb new file mode 100644 index 00000000000..d05d5c7e72f --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/session.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class Session < BasicSession + def initialize(opts) + @check_in = opts[:check_in] + @token = Token.build(check_in: check_in) + @redis_handler = RedisHandler.build(check_in: check_in) + end + end + end +end diff --git a/modules/check_in/app/services/v1/lorota/token.rb b/modules/check_in/app/services/v1/lorota/token.rb new file mode 100644 index 00000000000..7b5be75998a --- /dev/null +++ b/modules/check_in/app/services/v1/lorota/token.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module V1 + module Lorota + class Token < BasicToken + def initialize(opts) + @settings = Settings.check_in.lorota_v1 + @check_in = opts[:check_in] + @claims_token = ClaimsToken.build(check_in: check_in).sign_assertion + @request = Request.build(claims_token: claims_token) + end + + def fetch + resp = request.post("/#{base_path}/token", auth_params) + + self.access_token = Oj.load(resp.body)&.fetch('token') + self + end + + def auth_params + { + SSN4: check_in.last4, + lastName: check_in.last_name + } + end + end + end +end diff --git a/modules/check_in/config/routes.rb b/modules/check_in/config/routes.rb index 8f4f8f90714..b0c895983ce 100644 --- a/modules/check_in/config/routes.rb +++ b/modules/check_in/config/routes.rb @@ -11,7 +11,7 @@ end namespace :v1, defaults: { format: :json } do - resources :patient_check_ins, only: %i[index create] + resources :patient_check_ins, only: %i[show create] resources :sessions, only: %i[show create] end end diff --git a/modules/check_in/lib/check_in/engine.rb b/modules/check_in/lib/check_in/engine.rb index f4495324e93..acc1b94390c 100644 --- a/modules/check_in/lib/check_in/engine.rb +++ b/modules/check_in/lib/check_in/engine.rb @@ -8,5 +8,8 @@ class Engine < ::Rails::Engine initializer 'model_core.factories', after: 'factory_bot.set_factory_paths' do FactoryBot.definition_file_paths << File.expand_path('../../spec/factories', __dir__) if defined?(FactoryBot) end + + middleware.use ActionDispatch::Cookies + middleware.use ActionDispatch::Session::CookieStore end end diff --git a/modules/check_in/spec/models/check_in/check_in_with_auth_spec.rb b/modules/check_in/spec/models/check_in/check_in_with_auth_spec.rb new file mode 100644 index 00000000000..3b775363c4d --- /dev/null +++ b/modules/check_in/spec/models/check_in/check_in_with_auth_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe CheckIn::CheckInWithAuth do + subject { described_class } + + describe 'constants' do + it 'has a LAST_FOUR_REGEX regex' do + expect(subject::LAST_FOUR_REGEX).to eq(/^[0-9]{4}$/) + end + + it 'has a LAST_NAME_REGEX regex' do + expect(subject::LAST_NAME_REGEX).to eq(/^.{1,600}$/) + end + end + + describe '.build' do + it 'returns an instance of CheckInWithAuth' do + expect(subject.build({})).to be_an_instance_of(CheckIn::CheckInWithAuth) + end + end + + describe 'attributes' do + it 'responds to uuid' do + expect(subject.build({}).respond_to?(:uuid)).to be(true) + end + + it 'responds to last4' do + expect(subject.build({}).respond_to?(:last4)).to be(true) + end + + it 'responds to last_name' do + expect(subject.build({}).respond_to?(:last_name)).to be(true) + end + end + + describe '#valid?' do + context 'when valid params' do + it 'returns true' do + params_hsh = { + data: { + uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + last4: '5555', + last_name: 'Johnson' + } + } + + expect(subject.build(params_hsh).valid?).to be(true) + end + end + + context 'when invalid uuid' do + it 'returns false' do + params_hsh = { + uuid: 'd602d9eb', + last4: '5555', + last_name: 'Johnson' + } + + expect(subject.build(params_hsh).valid?).to be(false) + end + end + end + + describe '#client_error' do + it 'has a response' do + hsh = { error: true, message: 'Invalid uuid, last4 or last name!' } + params_hsh = { + id: 'd602d9eb', + last4: '5555', + last_name: 'Johnson' + } + error = subject.build(params_hsh).client_error + + expect(error.body).to eq(hsh) + expect(error.status).to eq(400) + end + end +end diff --git a/modules/check_in/spec/request/v1/patient_check_ins_request_spec.rb b/modules/check_in/spec/request/v1/patient_check_ins_request_spec.rb index 6bf33f10eed..73ef26208e9 100644 --- a/modules/check_in/spec/request/v1/patient_check_ins_request_spec.rb +++ b/modules/check_in/spec/request/v1/patient_check_ins_request_spec.rb @@ -5,6 +5,13 @@ RSpec.describe 'V1::PatientCheckIns', type: :request do let(:id) { 'd602d9eb-9a31-484f-9637-13ab0b507e0d' } let(:check_in) { CheckIn::PatientCheckIn.build(uuid: id) } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + + Rails.cache.clear + end describe 'POST `create`' do before do @@ -16,11 +23,32 @@ context 'when valid UUID' do let(:post_params) { { params: { patient_check_ins: { id: id } } } } + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + let(:data) do + { + data: { + jwt: 'full_jwt_token' + } + } + end let(:resp) do { 'data' => 'Successful checkin', 'status' => 200 } end it 'returns a success hash' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(data) + + post '/check_in/v1/sessions', session_params post '/check_in/v1/patient_check_ins', post_params expect(JSON.parse(response.body)).to eq(resp) @@ -29,15 +57,104 @@ context 'when invalid UUID' do let(:post_params) { { params: { patient_check_ins: { id: '1234' } } } } + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + let(:data) do + { + data: { + jwt: 'full_jwt_token' + } + } + end let(:resp) do - { 'data' => { 'error' => true, 'message' => 'Invalid uuid d602d9eb' } } + { 'data' => { 'error' => true, 'message' => 'Check-in failed' }, 'status' => 403 } end it 'returns a data hash with invalid UUID' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(data) + + post '/check_in/v1/sessions', session_params post '/check_in/v1/patient_check_ins', post_params expect(JSON.parse(response.body)).to eq(resp) end end end + + describe 'GET `show`' do + before do + allow(Flipper).to receive(:enabled?) + .with('check_in_experience_low_authentication_enabled').and_return(true) + allow_any_instance_of(::V1::Chip::Service).to receive(:check_in).and_return(check_in) + end + + context 'when no jwt' do + let(:resp) do + { + 'id' => id, + 'scope' => 'read.basic', + 'payload' => { + 'full' => 'false' + } + } + end + + it 'returns the partial appointment details' do + allow_any_instance_of(::V1::Lorota::BasicService).to receive(:get_check_in).and_return(resp) + + get "/check_in/v1/patient_check_ins/#{id}" + + expect(JSON.parse(response.body)).to eq(resp) + end + end + + context 'when jwt' do + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + let(:data) do + { + data: { + jwt: 'full_jwt_token' + } + } + end + let(:resp) do + { + 'id' => id, + 'scope' => 'read.full', + 'payload' => { + 'full' => 'true' + } + } + end + + it 'returns the full appointment details' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(data) + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_check_in).and_return(resp) + + post '/check_in/v1/sessions', session_params + get "/check_in/v1/patient_check_ins/#{id}" + + expect(JSON.parse(response.body)).to eq(resp) + end + end + end end diff --git a/modules/check_in/spec/request/v1/sessions_request_spec.rb b/modules/check_in/spec/request/v1/sessions_request_spec.rb new file mode 100644 index 00000000000..57547e99a41 --- /dev/null +++ b/modules/check_in/spec/request/v1/sessions_request_spec.rb @@ -0,0 +1,165 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'V1::SessionsController', type: :request do + let(:id) { 'd602d9eb-9a31-484f-9637-13ab0b507e0d' } + let(:basic_check_in) { CheckIn::PatientCheckIn.build(uuid: id) } + let(:check_in) do + CheckIn::CheckInWithAuth.build(uuid: id, last4: '1234', last_name: 'Johnson') + end + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + allow(Flipper).to receive(:enabled?) + .with('check_in_experience_low_authentication_enabled').and_return(true) + + Rails.cache.clear + end + + describe 'GET `show`' do + context 'when no jwt' do + let(:resp) do + { + 'data' => { + 'permissions' => 'read.basic', + 'uuid' => 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + 'status' => 'success', + 'jwt' => 'basic-123abc' + }, + 'status' => 200 + } + end + + it 'returns a basic token' do + allow_any_instance_of(::V1::Lorota::BasicService).to receive(:get_or_create_token).and_return(resp) + + get "/check_in/v1/sessions/#{id}" + + expect(JSON.parse(response.body)).to eq(resp) + end + end + + context 'when jwt' do + let(:resp) do + { + 'data' => { + 'permissions' => 'read.full', + 'uuid' => 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + 'status' => 'success', + 'jwt' => 'full_jwt_token' + }, + 'status' => 200 + } + end + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + let(:data) do + { + data: { + jwt: 'full_jwt_token' + } + } + end + + it 'returns a full token' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(data) + + post '/check_in/v1/sessions', session_params + get "/check_in/v1/sessions/#{id}" + + expect(JSON.parse(response.body)).to eq(resp) + end + end + end + + describe 'POST `create`' do + context 'when no jwt' do + let(:resp) do + { + 'data' => { + 'permissions' => 'read.full', + 'uuid' => 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + 'status' => 'success', + 'jwt' => 'full-123abc' + }, + 'status' => 200 + } + end + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + + it 'returns a basic token' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(resp) + + post '/check_in/v1/sessions', session_params + + expect(JSON.parse(response.body)).to eq(resp) + end + end + + context 'when jwt' do + let(:resp) do + { + 'data' => { + 'permissions' => 'read.full', + 'uuid' => 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + 'status' => 'success', + 'jwt' => 'full_jwt_token' + }, + 'status' => 200 + } + end + let(:session_params) do + { + params: { + session: { + uuid: id, + last4: '5555', + last_name: 'Johnson' + } + } + } + end + let(:data) do + { + data: { + jwt: 'full_jwt_token' + } + } + end + + it 'returns a full token' do + allow_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).and_return(resp) + expect_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).once + + post '/check_in/v1/sessions', session_params + + expect_any_instance_of(::V1::Lorota::Service).to receive(:get_or_create_token).exactly(0).times + + post '/check_in/v1/sessions', session_params + + expect(JSON.parse(response.body)).to eq(resp) + end + end + end +end diff --git a/modules/check_in/spec/services/v1/chip/service_spec.rb b/modules/check_in/spec/services/v1/chip/service_spec.rb index 3b816009a6f..1d0cb0574d8 100644 --- a/modules/check_in/spec/services/v1/chip/service_spec.rb +++ b/modules/check_in/spec/services/v1/chip/service_spec.rb @@ -8,6 +8,13 @@ let(:id) { 'd602d9eb-9a31-484f-9637-13ab0b507e0d' } let(:valid_check_in) { CheckIn::PatientCheckIn.build(uuid: id) } let(:invalid_check_in) { CheckIn::PatientCheckIn.build(uuid: '1234') } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + + Rails.cache.clear + end describe '.build' do it 'returns an instance of Service' do @@ -31,6 +38,12 @@ hsh = { data: faraday_response.body, status: faraday_response.status } + Rails.cache.write( + 'check_in_lorota_v1_d602d9eb-9a31-484f-9637-13ab0b507e0d_read.full', + '12345', + namespace: 'check-in-lorota-v1-cache' + ) + expect(subject.build(valid_check_in).create_check_in).to eq(hsh) end end diff --git a/modules/check_in/spec/services/v1/lorota/basic_redis_handler_spec.rb b/modules/check_in/spec/services/v1/lorota/basic_redis_handler_spec.rb new file mode 100644 index 00000000000..8ec7ace6ee8 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/basic_redis_handler_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::BasicRedisHandler do + subject { described_class } + + let(:check_in) { CheckIn::PatientCheckIn.build(uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d') } + let(:redis_handler) { subject.build(check_in: check_in) } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + + Rails.cache.clear + end + + describe 'attributes' do + it 'responds to check_in' do + expect(redis_handler.respond_to?(:check_in)).to be(true) + end + + it 'responds to settings' do + expect(redis_handler.respond_to?(:settings)).to be(true) + end + end + + describe '.build' do + it 'returns an instance of RedisHandler' do + expect(redis_handler).to be_an_instance_of(V1::Lorota::BasicRedisHandler) + end + end + + describe '#get' do + context 'when cache exists' do + it 'returns the cached value' do + Rails.cache.write( + 'check_in_lorota_v1_d602d9eb-9a31-484f-9637-13ab0b507e0d_read.basic', + '12345', + namespace: 'check-in-lorota-v1-cache' + ) + + expect(redis_handler.get).to eq('12345') + end + end + + context 'when cache does not exist' do + it 'returns nil' do + expect(redis_handler.get).to eq(nil) + end + end + end + + describe '#save' do + it 'is true' do + allow_any_instance_of(V1::Lorota::BasicToken).to receive(:access_token).and_return('12345') + allow_any_instance_of(subject).to receive(:token) + .and_return(V1::Lorota::BasicToken.build(check_in: check_in)) + + expect(redis_handler.save).to eq(true) + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/basic_service_spec.rb b/modules/check_in/spec/services/v1/lorota/basic_service_spec.rb new file mode 100644 index 00000000000..5d05ce0ff03 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/basic_service_spec.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::BasicService do + subject { described_class } + + let(:id) { 'd602d9eb-9a31-484f-9637-13ab0b507e0d' } + let(:valid_check_in) { CheckIn::PatientCheckIn.build(uuid: id) } + let(:invalid_check_in) { CheckIn::PatientCheckIn.build(uuid: '1234') } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + + Rails.cache.clear + end + + describe '.build' do + it 'returns an instance of Service' do + expect(subject.build(check_in: valid_check_in)).to be_an_instance_of(V1::Lorota::BasicService) + end + end + + describe '#get_or_create_token' do + it 'returns data from redis' do + allow_any_instance_of(V1::Lorota::BasicSession).to receive(:from_redis).and_return('123abc') + + hsh = { + data: { + permissions: 'read.basic', + uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + status: 'success', + jwt: '123abc' + }, + status: 200 + } + + expect(subject.build(check_in: valid_check_in).get_or_create_token).to eq(hsh) + end + + it 'returns data from lorota' do + allow_any_instance_of(V1::Lorota::BasicSession).to receive(:from_redis).and_return(nil) + allow_any_instance_of(V1::Lorota::BasicSession).to receive(:from_lorota).and_return('abc123') + + hsh = { + data: { + permissions: 'read.basic', + uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + status: 'success', + jwt: 'abc123' + }, + status: 200 + } + + expect(subject.build(check_in: valid_check_in).get_or_create_token).to eq(hsh) + end + end + + describe '#get_check_in' do + let(:data) do + Faraday::Response.new(body: '{"foo":"bar"}', status: 200) + end + + it 'return check-in data' do + allow_any_instance_of(V1::Lorota::BasicSession).to receive(:from_redis).and_return('123abc') + allow_any_instance_of(V1::Lorota::Request).to receive(:get).with(anything).and_return(data) + + expect(subject.build(check_in: valid_check_in).get_check_in).to eq({ 'foo' => 'bar' }) + end + end + + describe '#base_path' do + it 'returns base_path' do + expect(subject.build(check_in: valid_check_in).base_path).to eq('dev') + end + end + + describe '#permissions' do + it 'returns permissions' do + expect(subject.build(check_in: valid_check_in).permissions).to eq('read.basic') + end + end + + describe '#format_data' do + it 'returns formatted data' do + hsh = { + data: { + permissions: 'read.basic', + uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + status: 'success', + jwt: '123' + }, + status: 200 + } + + expect(subject.build(check_in: valid_check_in).format_data('123')).to eq(hsh) + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/basic_session_spec.rb b/modules/check_in/spec/services/v1/lorota/basic_session_spec.rb new file mode 100644 index 00000000000..d5510269930 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/basic_session_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::BasicSession do + subject { described_class.build(check_in: check_in) } + + let(:check_in) { CheckIn::PatientCheckIn.build(uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d') } + let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) } + + before do + allow(Rails).to receive(:cache).and_return(memory_store) + + Rails.cache.clear + end + + describe 'attributes' do + it 'responds to redis_handler' do + expect(subject.respond_to?(:redis_handler)).to be(true) + end + + it 'responds to token' do + expect(subject.respond_to?(:token)).to be(true) + end + it 'responds to check_in' do + expect(subject.respond_to?(:check_in)).to be(true) + end + end + + describe '.build' do + it 'returns an instance of Session' do + expect(subject).to be_an_instance_of(V1::Lorota::BasicSession) + end + end + + describe '#from_redis' do + context 'when cache exists' do + it 'returns the token' do + Rails.cache.write( + 'check_in_lorota_v1_d602d9eb-9a31-484f-9637-13ab0b507e0d_read.basic', + '12345', + namespace: 'check-in-lorota-v1-cache' + ) + + expect(subject.from_redis).to eq('12345') + end + end + + context 'when cache does not exist' do + it 'returns nil' do + allow_any_instance_of(V1::Lorota::BasicRedisHandler).to receive(:get).and_return(nil) + + expect(subject.from_redis).to eq(nil) + end + end + end + + describe '#from_lorota' do + let(:token) { V1::Lorota::BasicToken.build(check_in: check_in) } + + it 'returns the token' do + allow(token).to receive(:access_token).and_return('12345') + allow_any_instance_of(V1::Lorota::BasicToken).to receive(:fetch).and_return(token) + + expect(subject.from_lorota).to eq('12345') + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/basic_token_spec.rb b/modules/check_in/spec/services/v1/lorota/basic_token_spec.rb new file mode 100644 index 00000000000..c21c2de4eee --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/basic_token_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::BasicToken do + subject { described_class.build(check_in: check_in) } + + let(:check_in) { CheckIn::PatientCheckIn.build(uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d') } + + describe 'attributes' do + it 'responds to request' do + expect(subject.respond_to?(:request)).to be(true) + end + + it 'responds to claims_token' do + expect(subject.respond_to?(:claims_token)).to be(true) + end + + it 'responds to access_token' do + expect(subject.respond_to?(:access_token)).to be(true) + end + + it 'responds to check_in' do + expect(subject.respond_to?(:check_in)).to be(true) + end + end + + describe '.build' do + it 'returns an instance of Token' do + expect(subject).to be_an_instance_of(V1::Lorota::BasicToken) + end + end + + describe '#fetch' do + let(:token) do + 'eyJraWQiOiJRMFZKbEt0TU9rYUxXTEtxdXhsTllHQzFRLWMtblQzYjRWVlJLaXB4TThzIiwiYWxnIj' + end + let(:faraday_response) { double('Faraday::Response', body: { 'token' => token }.to_json) } + + before do + allow_any_instance_of(V1::Lorota::Request).to receive(:post).with(anything, anything).and_return(faraday_response) + end + + it 'returns an instance of Token' do + expect(subject.fetch).to be_an_instance_of(V1::Lorota::BasicToken) + end + + it 'has an access_token value' do + expect(subject.fetch.access_token).to eq(token) + end + end + + describe '#base_path' do + it 'returns base_path' do + expect(subject.base_path).to eq('dev') + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/request_spec.rb b/modules/check_in/spec/services/v1/lorota/request_spec.rb new file mode 100644 index 00000000000..fe843423ac0 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/request_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::Request do + subject { described_class } + + describe '.build' do + it 'returns an instance of Request' do + expect(subject.build).to be_an_instance_of(V1::Lorota::Request) + end + end + + describe '#get' do + let(:conn) { double('Faraday::Connection') } + + it 'connection is called with get' do + allow_any_instance_of(Faraday::Connection).to receive(:get).with(anything).and_return(anything) + + expect_any_instance_of(Faraday::Connection).to receive(:get) + .with('/dev/data/d602d9eb-9a31-484f-9637-13ab0b507e0d').once + + subject.build.get('/dev/data/d602d9eb-9a31-484f-9637-13ab0b507e0d') + end + end + + describe '#post' do + it 'connection is called with post' do + allow_any_instance_of(Faraday::Connection).to receive(:post).with(anything).and_return(anything) + + expect_any_instance_of(Faraday::Connection).to receive(:post) + .with('/dev/token').once + + subject.build.post('/dev/token', {}) + end + end + + describe '#connection' do + let(:stubs) { Faraday::Adapter::Test::Stubs.new } + let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } } + + after do + Faraday.default_connection = nil + end + + it 'creates a new instance just once' do + allow(Faraday).to receive(:new).and_return(conn) + + expect(Faraday).to receive(:new).once + + subject.build.connection + end + end + + describe '#headers' do + it 'has default headers' do + hsh = { + 'Content-Type' => 'application/json', + 'x-api-key' => 'Xc7k35oE2H9aDeUEpeGa38PzAHyLT9jb5HiKeBfs', + 'x-apigw-api-id' => '22t00c6f97' + } + + expect(subject.build.headers).to eq(hsh) + end + end + + describe '#settings' do + it 'has a url' do + url = 'https://vpce-06399548ef94bdb41-lk4qp2nd.execute-api.us-gov-west-1.vpce.amazonaws.com' + + expect(subject.build.url).to eq(url) + end + + it 'has a service_name' do + expect(subject.build.service_name).to eq('LoROTA-API') + end + + it 'has an api_id' do + expect(subject.build.api_id).to eq('22t00c6f97') + end + + it 'has an api_key' do + expect(subject.build.api_key).to eq('Xc7k35oE2H9aDeUEpeGa38PzAHyLT9jb5HiKeBfs') + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/response_spec.rb b/modules/check_in/spec/services/v1/lorota/response_spec.rb new file mode 100644 index 00000000000..e56d56885c6 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/response_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::Response do + subject { described_class } + + describe '#handle' do + context 'when status 200' do + context 'when json string' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: { foo: 'bar' }, status: 200) + hsh = { data: { foo: 'bar' }, status: 200 } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + + context 'when non json string' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: 'bar', status: 200) + hsh = { data: 'bar', status: 200 } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + end + + context 'when status 404' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: 'Not found', status: 404) + hsh = { data: { error: true, message: 'We could not find that resource' }, status: resp.status } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + + context 'when status 403' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: 'Forbidden', status: 403) + hsh = { data: { error: true, message: 'Forbidden' }, status: resp.status } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + + context 'when status 401' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: 'Unauthorized', status: 401) + hsh = { data: { error: true, message: 'Unauthorized' }, status: resp.status } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + + context 'when status 400' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: { error: true, message: 'Invalid uuid' }, status: 400) + hsh = { data: { error: true, message: 'Invalid uuid' }, status: resp.status } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + + context 'when status 500' do + it 'returns a formatted response' do + resp = Faraday::Response.new(body: 'Something went wrong', status: 500) + hsh = { data: { error: true, message: 'Something went wrong' }, status: resp.status } + + expect(subject.build(response: resp).handle).to eq(hsh) + end + end + end +end diff --git a/modules/check_in/spec/services/v1/lorota/token_spec.rb b/modules/check_in/spec/services/v1/lorota/token_spec.rb new file mode 100644 index 00000000000..76bca0f9a43 --- /dev/null +++ b/modules/check_in/spec/services/v1/lorota/token_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe V1::Lorota::Token do + subject { described_class.build(check_in: check_in) } + + let(:check_in) do + CheckIn::CheckInWithAuth.build( + uuid: 'd602d9eb-9a31-484f-9637-13ab0b507e0d', + last4: '1234', + last_name: 'Johnson' + ) + end + + describe 'attributes' do + it 'responds to request' do + expect(subject.respond_to?(:request)).to be(true) + end + + it 'responds to claims_token' do + expect(subject.respond_to?(:claims_token)).to be(true) + end + + it 'responds to check_in' do + expect(subject.respond_to?(:check_in)).to be(true) + end + + it 'responds to settings' do + expect(subject.respond_to?(:settings)).to be(true) + end + end + + describe '.build' do + it 'returns an instance of Token' do + expect(subject).to be_an_instance_of(V1::Lorota::Token) + end + end + + describe '#fetch' do + let(:token) do + 'eyJraWQiOiJRMFZKbEt0TU9rYUxXTEtxdXhsTllHQzFRLWMtblQzYjRWVlJLaXB4TThzIiwiYWxnIj' + end + let(:faraday_response) { double('Faraday::Response', body: { 'token' => token }.to_json) } + + before do + allow_any_instance_of(V1::Lorota::Request).to receive(:post).with(anything, anything).and_return(faraday_response) + end + + it 'returns an instance of Token' do + expect(subject.fetch).to be_an_instance_of(V1::Lorota::Token) + end + + it 'has an access_token value' do + expect(subject.fetch.access_token).to eq(token) + end + end + + describe '#base_path' do + it 'returns base_path' do + expect(subject.base_path).to eq('dev') + end + end +end