From 7b1264d14016143e365451d9c79d57f759f3345b Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Thu, 8 Jul 2021 08:46:28 +0100 Subject: [PATCH 1/3] fix(imports): change imports from main barrel into internal barrels --- src/SASViyaApiClient.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/SASViyaApiClient.ts b/src/SASViyaApiClient.ts index 068e780..bfcdb81 100644 --- a/src/SASViyaApiClient.ts +++ b/src/SASViyaApiClient.ts @@ -25,16 +25,13 @@ import { import { formatDataForRequest } from './utils/formatDataForRequest' import { SessionManager } from './SessionManager' import { ContextManager } from './ContextManager' +import { timestampToYYYYMMDDHHMMSS } from '@sasjs/utils/time' import { - timestampToYYYYMMDDHHMMSS, isAccessTokenExpiring, - isRefreshTokenExpiring, - Logger, - LogLevel, - SasAuthResponse, - MacroVar, - AuthConfig -} from '@sasjs/utils' + isRefreshTokenExpiring +} from '@sasjs/utils/auth' +import { Logger, LogLevel } from '@sasjs/utils/logger' +import { SasAuthResponse, MacroVar, AuthConfig } from '@sasjs/utils/types' import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired' import { RequestClient } from './request/RequestClient' import { prefixMessage } from '@sasjs/utils/error' From d4ebef4290cd12582221b6c88426e839077b03a4 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Tue, 13 Jul 2021 14:50:46 +0300 Subject: [PATCH 2/3] fix(session): provide more info if could not get session state --- src/SessionManager.ts | 32 +++++++++++++++++-------- src/request/RequestClient.ts | 12 +++++++--- src/request/Sas9RequestClient.ts | 2 +- src/types/errors/NoSessionStateError.ts | 15 ++++++++++++ src/types/errors/index.ts | 1 + 5 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 src/types/errors/NoSessionStateError.ts diff --git a/src/SessionManager.ts b/src/SessionManager.ts index 914a686..eb195a0 100644 --- a/src/SessionManager.ts +++ b/src/SessionManager.ts @@ -1,4 +1,5 @@ -import { Session, Context, CsrfToken, SessionVariable } from './types' +import { Session, Context, SessionVariable } from './types' +import { NoSessionStateError } from './types/errors' import { asyncForEach, isUrl } from './utils' import { prefixMessage } from '@sasjs/utils/error' import { RequestClient } from './request/RequestClient' @@ -173,13 +174,14 @@ export class SessionManager { this.printedSessionState.printed = true } - const state = await this.getSessionState( - `${this.serverUrl}${stateLink.href}?wait=30`, - etag!, - accessToken - ).catch((err) => { - throw prefixMessage(err, 'Error while getting session state.') - }) + const { result: state, responseStatus: responseStatus } = + await this.getSessionState( + `${this.serverUrl}${stateLink.href}?wait=30`, + etag!, + accessToken + ).catch((err) => { + throw prefixMessage(err, 'Error while getting session state.') + }) sessionState = state.trim() @@ -198,7 +200,14 @@ export class SessionManager { resolve(this.waitForSession(session, etag, accessToken)) } else { - reject('Could not get session state.') + reject( + new NoSessionStateError( + responseStatus, + this.serverUrl + stateLink.href, + session.links.find((l: any) => l.rel === 'log') + ?.href as string + ) + ) } } @@ -217,7 +226,10 @@ export class SessionManager { ) { return await this.requestClient .get(url, accessToken, 'text/plain', { 'If-None-Match': etag }) - .then((res) => res.result as string) + .then((res) => ({ + result: res.result as string, + responseStatus: res.status + })) .catch((err) => { throw err }) diff --git a/src/request/RequestClient.ts b/src/request/RequestClient.ts index eb6aac2..704401e 100644 --- a/src/request/RequestClient.ts +++ b/src/request/RequestClient.ts @@ -84,7 +84,7 @@ export class RequestClient implements HttpClient { contentType: string = 'application/json', overrideHeaders: { [key: string]: string | number } = {}, debug: boolean = false - ): Promise<{ result: T; etag: string }> { + ): Promise<{ result: T; etag: string; status: number }> { const headers = { ...this.getHeaders(accessToken, contentType), ...overrideHeaders @@ -438,9 +438,15 @@ export class RequestClient implements HttpClient { includeSAS9Log = true } - let responseToReturn: { result: T; etag: any; log?: string } = { + let responseToReturn: { + result: T + etag: any + log?: string + status: number + } = { result: parsedResponse as T, - etag + etag, + status: response.status } if (includeSAS9Log) { diff --git a/src/request/Sas9RequestClient.ts b/src/request/Sas9RequestClient.ts index eedb3ef..5fb4750 100644 --- a/src/request/Sas9RequestClient.ts +++ b/src/request/Sas9RequestClient.ts @@ -39,7 +39,7 @@ export class Sas9RequestClient extends RequestClient { contentType: string = 'application/json', overrideHeaders: { [key: string]: string | number } = {}, debug: boolean = false - ): Promise<{ result: T; etag: string }> { + ): Promise<{ result: T; etag: string; status: number }> { const headers = { ...this.getHeaders(accessToken, contentType), ...overrideHeaders diff --git a/src/types/errors/NoSessionStateError.ts b/src/types/errors/NoSessionStateError.ts new file mode 100644 index 0000000..3409b43 --- /dev/null +++ b/src/types/errors/NoSessionStateError.ts @@ -0,0 +1,15 @@ +export class NoSessionStateError extends Error { + constructor( + public serverResponseStatus: number, + public sessionStateUrl: string, + public logUrl: string + ) { + super( + `Could not get session state. Server responded with ${serverResponseStatus} whilst checking state: ${sessionStateUrl}` + ) + + this.name = 'NoSessionStatus' + + Object.setPrototypeOf(this, NoSessionStateError.prototype) + } +} diff --git a/src/types/errors/index.ts b/src/types/errors/index.ts index 3db6b72..72b63cc 100644 --- a/src/types/errors/index.ts +++ b/src/types/errors/index.ts @@ -5,3 +5,4 @@ export * from './JobExecutionError' export * from './LoginRequiredError' export * from './NotFoundError' export * from './ErrorResponse' +export * from './NoSessionStateError' From a5c9f11c7535720c4bd047477b97130ab4cf7473 Mon Sep 17 00:00:00 2001 From: Yury Shkoda Date: Wed, 14 Jul 2021 14:17:20 +0300 Subject: [PATCH 3/3] test(session): cover case when could not get session state --- src/test/SessionManager.spec.ts | 38 ++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/test/SessionManager.spec.ts b/src/test/SessionManager.spec.ts index 2af3855..c818d4f 100644 --- a/src/test/SessionManager.spec.ts +++ b/src/test/SessionManager.spec.ts @@ -1,7 +1,9 @@ import { SessionManager } from '../SessionManager' -import * as dotenv from 'dotenv' import { RequestClient } from '../request/RequestClient' +import { NoSessionStateError } from '../types/errors' +import * as dotenv from 'dotenv' import axios from 'axios' + jest.mock('axios') const mockedAxios = axios as jest.Mocked @@ -43,4 +45,38 @@ describe('SessionManager', () => { ).resolves.toEqual(expectedResponse) }) }) + + describe('waitForSession', () => { + it('should reject with NoSessionStateError if SAS server did not provide session state', async () => { + const responseStatus = 304 + + mockedAxios.get.mockImplementation(() => + Promise.resolve({ data: '', status: responseStatus }) + ) + + await expect( + sessionManager['waitForSession']( + { + id: 'id', + state: '', + links: [ + { rel: 'state', href: '', uri: '', type: '', method: 'GET' } + ], + attributes: { + sessionInactiveTimeout: 0 + }, + creationTimeStamp: '' + }, + null, + 'access_token' + ) + ).rejects.toEqual( + new NoSessionStateError( + responseStatus, + process.env.SERVER_URL as string, + 'logUrl' + ) + ) + }) + }) })