1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-17 09:00:06 +00:00

Merge branch 'master' into allanbowe-patch-1

This commit is contained in:
Allan Bowe
2021-07-14 20:41:51 +03:00
committed by GitHub
7 changed files with 90 additions and 23 deletions

View File

@@ -25,16 +25,13 @@ import {
import { formatDataForRequest } from './utils/formatDataForRequest' import { formatDataForRequest } from './utils/formatDataForRequest'
import { SessionManager } from './SessionManager' import { SessionManager } from './SessionManager'
import { ContextManager } from './ContextManager' import { ContextManager } from './ContextManager'
import { timestampToYYYYMMDDHHMMSS } from '@sasjs/utils/time'
import { import {
timestampToYYYYMMDDHHMMSS,
isAccessTokenExpiring, isAccessTokenExpiring,
isRefreshTokenExpiring, isRefreshTokenExpiring
Logger, } from '@sasjs/utils/auth'
LogLevel, import { Logger, LogLevel } from '@sasjs/utils/logger'
SasAuthResponse, import { SasAuthResponse, MacroVar, AuthConfig } from '@sasjs/utils/types'
MacroVar,
AuthConfig
} from '@sasjs/utils'
import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired' import { isAuthorizeFormRequired } from './auth/isAuthorizeFormRequired'
import { RequestClient } from './request/RequestClient' import { RequestClient } from './request/RequestClient'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'

View File

@@ -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 { asyncForEach, isUrl } from './utils'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from './request/RequestClient' import { RequestClient } from './request/RequestClient'
@@ -173,13 +174,14 @@ export class SessionManager {
this.printedSessionState.printed = true this.printedSessionState.printed = true
} }
const state = await this.getSessionState( const { result: state, responseStatus: responseStatus } =
`${this.serverUrl}${stateLink.href}?wait=30`, await this.getSessionState(
etag!, `${this.serverUrl}${stateLink.href}?wait=30`,
accessToken etag!,
).catch((err) => { accessToken
throw prefixMessage(err, 'Error while getting session state.') ).catch((err) => {
}) throw prefixMessage(err, 'Error while getting session state.')
})
sessionState = state.trim() sessionState = state.trim()
@@ -198,7 +200,14 @@ export class SessionManager {
resolve(this.waitForSession(session, etag, accessToken)) resolve(this.waitForSession(session, etag, accessToken))
} else { } 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 return await this.requestClient
.get(url, accessToken, 'text/plain', { 'If-None-Match': etag }) .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) => { .catch((err) => {
throw err throw err
}) })

View File

@@ -84,7 +84,7 @@ export class RequestClient implements HttpClient {
contentType: string = 'application/json', contentType: string = 'application/json',
overrideHeaders: { [key: string]: string | number } = {}, overrideHeaders: { [key: string]: string | number } = {},
debug: boolean = false debug: boolean = false
): Promise<{ result: T; etag: string }> { ): Promise<{ result: T; etag: string; status: number }> {
const headers = { const headers = {
...this.getHeaders(accessToken, contentType), ...this.getHeaders(accessToken, contentType),
...overrideHeaders ...overrideHeaders
@@ -438,9 +438,15 @@ export class RequestClient implements HttpClient {
includeSAS9Log = true includeSAS9Log = true
} }
let responseToReturn: { result: T; etag: any; log?: string } = { let responseToReturn: {
result: T
etag: any
log?: string
status: number
} = {
result: parsedResponse as T, result: parsedResponse as T,
etag etag,
status: response.status
} }
if (includeSAS9Log) { if (includeSAS9Log) {

View File

@@ -39,7 +39,7 @@ export class Sas9RequestClient extends RequestClient {
contentType: string = 'application/json', contentType: string = 'application/json',
overrideHeaders: { [key: string]: string | number } = {}, overrideHeaders: { [key: string]: string | number } = {},
debug: boolean = false debug: boolean = false
): Promise<{ result: T; etag: string }> { ): Promise<{ result: T; etag: string; status: number }> {
const headers = { const headers = {
...this.getHeaders(accessToken, contentType), ...this.getHeaders(accessToken, contentType),
...overrideHeaders ...overrideHeaders

View File

@@ -1,7 +1,9 @@
import { SessionManager } from '../SessionManager' import { SessionManager } from '../SessionManager'
import * as dotenv from 'dotenv'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import { NoSessionStateError } from '../types/errors'
import * as dotenv from 'dotenv'
import axios from 'axios' import axios from 'axios'
jest.mock('axios') jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios> const mockedAxios = axios as jest.Mocked<typeof axios>
@@ -43,4 +45,38 @@ describe('SessionManager', () => {
).resolves.toEqual(expectedResponse) ).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'
)
)
})
})
}) })

View File

@@ -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)
}
}

View File

@@ -5,3 +5,4 @@ export * from './JobExecutionError'
export * from './LoginRequiredError' export * from './LoginRequiredError'
export * from './NotFoundError' export * from './NotFoundError'
export * from './ErrorResponse' export * from './ErrorResponse'
export * from './NoSessionStateError'