mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-17 09:00:06 +00:00
Merge pull request #466 from sasjs/session-state-fix
fix(session): provide more info if could not get session state
This commit is contained in:
@@ -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
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
15
src/types/errors/NoSessionStateError.ts
Normal file
15
src/types/errors/NoSessionStateError.ts
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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'
|
||||||
|
|||||||
Reference in New Issue
Block a user