mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-09 13:30:04 +00:00
feat(session-manager): refactored and covered with tests
This commit is contained in:
@@ -14,12 +14,12 @@ export class SessionManager {
|
|||||||
private contextName: string,
|
private contextName: string,
|
||||||
private requestClient: RequestClient
|
private requestClient: RequestClient
|
||||||
) {
|
) {
|
||||||
console.log(`🤖[SessionManager constructor]🤖`)
|
|
||||||
if (serverUrl) isUrl(serverUrl)
|
if (serverUrl) isUrl(serverUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private sessions: Session[] = []
|
private sessions: Session[] = []
|
||||||
private currentContext: Context | null = null
|
private currentContext: Context | null = null
|
||||||
|
private settingContext: boolean = false
|
||||||
private _debug: boolean = false
|
private _debug: boolean = false
|
||||||
private printedSessionState = {
|
private printedSessionState = {
|
||||||
printed: false,
|
printed: false,
|
||||||
@@ -34,164 +34,206 @@ export class SessionManager {
|
|||||||
this._debug = value
|
this._debug = value
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSession(accessToken?: string) {
|
private isSessionValid(session: Session) {
|
||||||
console.log(`🤖[]🤖`)
|
if (!session) return false
|
||||||
console.log(`🤖[---- SessionManager getSession start]🤖`)
|
|
||||||
console.log(
|
const secondsSinceSessionCreation =
|
||||||
`🤖[this.sessions]🤖`,
|
(new Date().getTime() - new Date(session.creationTimeStamp).getTime()) /
|
||||||
this.sessions.map((session: any) => session.id)
|
1000
|
||||||
|
|
||||||
|
if (
|
||||||
|
!session!.attributes ||
|
||||||
|
secondsSinceSessionCreation >= session!.attributes.sessionInactiveTimeout
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeSessionFromPull(session: Session) {
|
||||||
|
this.sessions = this.sessions.filter((ses) => ses.id !== session.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeExpiredSessions() {
|
||||||
|
this.sessions = this.sessions.filter((session) =>
|
||||||
|
this.isSessionValid(session)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private throwErrors(errors: (Error | string)[], prefix?: string) {
|
||||||
|
throw prefix
|
||||||
|
? prefixMessage(new Error(errors.join('. ')), prefix)
|
||||||
|
: new Error(
|
||||||
|
errors
|
||||||
|
.map((err) =>
|
||||||
|
(err as Error).message ? (err as Error).message : err
|
||||||
|
)
|
||||||
|
.join('. ')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSession(accessToken?: string) {
|
||||||
|
const errors: (Error | string)[] = []
|
||||||
|
let isErrorThrown = false
|
||||||
|
|
||||||
|
const throwIfError = () => {
|
||||||
|
if (errors.length && !isErrorThrown) {
|
||||||
|
isErrorThrown = true
|
||||||
|
|
||||||
|
this.throwErrors(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeExpiredSessions()
|
||||||
|
|
||||||
if (this.sessions.length) {
|
if (this.sessions.length) {
|
||||||
const session = this.sessions[0]
|
const session = this.sessions[0]
|
||||||
|
|
||||||
this.createSessions(accessToken)
|
this.removeSessionFromPull(session)
|
||||||
this.createAndWaitForSession(accessToken)
|
|
||||||
|
|
||||||
// TODO: check secondsSinceSessionCreation
|
this.createSessions(accessToken).catch((err) => {
|
||||||
|
errors.push(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.createAndWaitForSession(accessToken).catch((err) => {
|
||||||
|
errors.push(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
throwIfError()
|
||||||
|
|
||||||
return session
|
return session
|
||||||
} else {
|
} else {
|
||||||
await this.createSessions(accessToken)
|
this.createSessions(accessToken).catch((err) => {
|
||||||
console.log(
|
errors.push(err)
|
||||||
`🤖[ 45 this.sessions]🤖`,
|
})
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
await this.createAndWaitForSession(accessToken)
|
|
||||||
console.log(
|
|
||||||
`🤖[ 50 this.sessions]🤖`,
|
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
const session = this.sessions.pop()
|
await this.createAndWaitForSession(accessToken).catch((err) => {
|
||||||
console.log(`🤖[session]🤖`, session!.id)
|
errors.push(err)
|
||||||
|
})
|
||||||
|
|
||||||
console.log(
|
this.removeExpiredSessions()
|
||||||
`🤖[59 this.sessions]🤖`,
|
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
const secondsSinceSessionCreation =
|
const session = this.sessions.pop()!
|
||||||
(new Date().getTime() -
|
|
||||||
new Date(session!.creationTimeStamp).getTime()) /
|
this.removeSessionFromPull(session)
|
||||||
1000
|
|
||||||
console.log(
|
throwIfError()
|
||||||
`🤖[secondsSinceSessionCreation]🤖`,
|
|
||||||
secondsSinceSessionCreation
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
!session!.attributes ||
|
|
||||||
secondsSinceSessionCreation >=
|
|
||||||
session!.attributes.sessionInactiveTimeout
|
|
||||||
) {
|
|
||||||
console.log(`🤖[54]🤖`, 54)
|
|
||||||
await this.createSessions(accessToken)
|
|
||||||
const freshSession = this.sessions.pop()
|
|
||||||
console.log(`🤖[freshSession]🤖`, freshSession!.id)
|
|
||||||
return freshSession
|
|
||||||
}
|
|
||||||
console.log(`🤖[60]🤖`, 60)
|
|
||||||
console.log(`🤖[---- SessionManager getSession end]🤖`)
|
|
||||||
console.log(`🤖[]🤖`)
|
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearSession(id: string, accessToken?: string) {
|
private getErrorMessage(
|
||||||
console.log(
|
err: any,
|
||||||
`🤖[clearSession this.sessions]🤖`,
|
url: string,
|
||||||
this.sessions.map((session: any) => session.id)
|
method: 'GET' | 'POST' | 'DELETE'
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
`${method} request to ${url} failed with status code ${
|
||||||
|
err?.response?.status || 'unknown'
|
||||||
|
}. ` + err?.response?.data?.message || ''
|
||||||
)
|
)
|
||||||
console.log(`🤖[SessionManager clearSession id]🤖`, id)
|
}
|
||||||
|
|
||||||
|
async clearSession(id: string, accessToken?: string) {
|
||||||
|
const url = `/compute/sessions/${id}`
|
||||||
|
|
||||||
return await this.requestClient
|
return await this.requestClient
|
||||||
.delete<Session>(`/compute/sessions/${id}`, accessToken)
|
.delete<Session>(url, accessToken)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.sessions = this.sessions.filter((s) => s.id !== id)
|
this.sessions = this.sessions.filter((s) => s.id !== id)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw prefixMessage(err, 'Error while deleting session. ')
|
throw prefixMessage(
|
||||||
|
this.getErrorMessage(err, url, 'DELETE'),
|
||||||
|
'Error while deleting session. '
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSessions(accessToken?: string) {
|
private async createSessions(accessToken?: string) {
|
||||||
console.log(`🤖[SessionManager createSessions]🤖`)
|
const errors: (Error | string)[] = []
|
||||||
|
|
||||||
if (!this.sessions.length) {
|
if (!this.sessions.length) {
|
||||||
if (!this.currentContext) {
|
|
||||||
await this.setCurrentContext(accessToken).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`🤖[createSessions start this.sessions]🤖`,
|
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
await asyncForEach(new Array(MAX_SESSION_COUNT), async () => {
|
await asyncForEach(new Array(MAX_SESSION_COUNT), async () => {
|
||||||
const createdSession = await this.createAndWaitForSession(
|
await this.createAndWaitForSession(accessToken).catch((err) => {
|
||||||
accessToken
|
errors.push(err)
|
||||||
).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// console.log(`🤖[createSessions new session id]🤖`, createdSession.id)
|
|
||||||
|
|
||||||
// this.sessions.push(createdSession)
|
|
||||||
}).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
if (errors.length) {
|
||||||
`🤖[createSessions end this.sessions]🤖`,
|
this.throwErrors(errors, 'Error while creating session. ')
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async waitForCurrentContext(): Promise<void> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
if (this.currentContext) {
|
||||||
|
this.settingContext = false
|
||||||
|
|
||||||
|
clearInterval(timer)
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private async createAndWaitForSession(accessToken?: string) {
|
private async createAndWaitForSession(accessToken?: string) {
|
||||||
console.log(`🤖[SessionManager createAndWaitForSession]🤖`)
|
if (!this.currentContext) {
|
||||||
|
if (!this.settingContext) {
|
||||||
|
await this.setCurrentContext(accessToken)
|
||||||
|
} else {
|
||||||
|
await this.waitForCurrentContext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${this.serverUrl}/compute/contexts/${
|
||||||
|
this.currentContext!.id
|
||||||
|
}/sessions`
|
||||||
|
|
||||||
const { result: createdSession, etag } = await this.requestClient
|
const { result: createdSession, etag } = await this.requestClient
|
||||||
.post<Session>(
|
.post<Session>(url, {}, accessToken)
|
||||||
`${this.serverUrl}/compute/contexts/${
|
|
||||||
this.currentContext!.id
|
|
||||||
}/sessions`,
|
|
||||||
{},
|
|
||||||
accessToken
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
`Error while creating session. ${this.getErrorMessage(
|
||||||
|
err,
|
||||||
|
url,
|
||||||
|
'POST'
|
||||||
|
)}`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.waitForSession(createdSession, etag, accessToken)
|
await this.waitForSession(createdSession, etag, accessToken)
|
||||||
|
|
||||||
console.log(
|
|
||||||
`🤖[createAndWaitForSession this.sessions.map((session: any) => session.id)]🤖`,
|
|
||||||
this.sessions.map((session: any) => session.id)
|
|
||||||
)
|
|
||||||
console.log(
|
|
||||||
`🤖[createAndWaitForSession adding createdSession.id]🤖`,
|
|
||||||
createdSession.id
|
|
||||||
)
|
|
||||||
|
|
||||||
this.sessions.push(createdSession)
|
this.sessions.push(createdSession)
|
||||||
|
|
||||||
return createdSession
|
return createdSession
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setCurrentContext(accessToken?: string) {
|
private async setCurrentContext(accessToken?: string) {
|
||||||
console.log(`🤖[SessionManager setCurrentContext]🤖`)
|
|
||||||
|
|
||||||
if (!this.currentContext) {
|
if (!this.currentContext) {
|
||||||
|
const url = `${this.serverUrl}/compute/contexts?limit=10000`
|
||||||
|
|
||||||
|
this.settingContext = true
|
||||||
|
|
||||||
const { result: contexts } = await this.requestClient
|
const { result: contexts } = await this.requestClient
|
||||||
.get<{
|
.get<{
|
||||||
items: Context[]
|
items: Context[]
|
||||||
}>(`${this.serverUrl}/compute/contexts?limit=10000`, accessToken)
|
}>(url, accessToken)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
`Error while getting list of contexts. ${this.getErrorMessage(
|
||||||
|
err,
|
||||||
|
url,
|
||||||
|
'GET'
|
||||||
|
)}`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const contextsList =
|
const contextsList =
|
||||||
@@ -215,26 +257,11 @@ export class SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATE
|
|
||||||
private getHeaders(accessToken?: string) {
|
|
||||||
const headers: any = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
|
|
||||||
private async waitForSession(
|
private async waitForSession(
|
||||||
session: Session,
|
session: Session,
|
||||||
etag: string | null,
|
etag: string | null,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
console.log(`🤖[SessionManager waitForSession]🤖`)
|
|
||||||
|
|
||||||
const logger = process.logger || console
|
const logger = process.logger || console
|
||||||
|
|
||||||
let sessionState = session.state
|
let sessionState = session.state
|
||||||
@@ -253,13 +280,14 @@ export class SessionManager {
|
|||||||
this.printedSessionState.printed = true
|
this.printedSessionState.printed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const url = `${this.serverUrl}${stateLink.href}?wait=30`
|
||||||
|
|
||||||
const { result: state, responseStatus: responseStatus } =
|
const { result: state, responseStatus: responseStatus } =
|
||||||
await this.getSessionState(
|
await this.getSessionState(url, etag!, accessToken).catch((err) => {
|
||||||
`${this.serverUrl}${stateLink.href}?wait=30`,
|
throw prefixMessage(
|
||||||
etag!,
|
this.getErrorMessage(err, url, 'GET'),
|
||||||
accessToken
|
'Error while getting session state. '
|
||||||
).catch((err) => {
|
)
|
||||||
throw prefixMessage(err, 'Error while getting session state.')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
sessionState = state.trim()
|
sessionState = state.trim()
|
||||||
@@ -296,7 +324,7 @@ export class SessionManager {
|
|||||||
|
|
||||||
return sessionState
|
return sessionState
|
||||||
} else {
|
} else {
|
||||||
throw 'Error while getting session state link.'
|
throw 'Error while getting session state link. '
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.loggedErrors = []
|
this.loggedErrors = []
|
||||||
@@ -310,8 +338,6 @@ export class SessionManager {
|
|||||||
etag: string,
|
etag: string,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
console.log(`🤖[SessionManager getSessionState]🤖`)
|
|
||||||
|
|
||||||
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) => ({
|
.then((res) => ({
|
||||||
@@ -319,13 +345,14 @@ export class SessionManager {
|
|||||||
responseStatus: res.status
|
responseStatus: res.status
|
||||||
}))
|
}))
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw err
|
throw prefixMessage(
|
||||||
|
this.getErrorMessage(err, url, 'GET'),
|
||||||
|
'Error while getting session state. '
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVariable(sessionId: string, variable: string, accessToken?: string) {
|
async getVariable(sessionId: string, variable: string, accessToken?: string) {
|
||||||
console.log(`🤖[SessionManager getVariable]🤖`)
|
|
||||||
|
|
||||||
return await this.requestClient
|
return await this.requestClient
|
||||||
.get<SessionVariable>(
|
.get<SessionVariable>(
|
||||||
`${this.serverUrl}/compute/sessions/${sessionId}/variables/${variable}`,
|
`${this.serverUrl}/compute/sessions/${sessionId}/variables/${variable}`,
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ import { RequestClient } from '../request/RequestClient'
|
|||||||
import * as dotenv from 'dotenv'
|
import * as dotenv from 'dotenv'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { Logger, LogLevel } from '@sasjs/utils'
|
import { Logger, LogLevel } from '@sasjs/utils'
|
||||||
import { Session } from '../types'
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
import { Session, Context } from '../types'
|
||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
const mockedAxios = axios as jest.Mocked<typeof axios>
|
const mockedAxios = axios as jest.Mocked<typeof axios>
|
||||||
|
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||||
|
|
||||||
describe('SessionManager', () => {
|
describe('SessionManager', () => {
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
@@ -14,9 +16,23 @@ describe('SessionManager', () => {
|
|||||||
const sessionManager = new SessionManager(
|
const sessionManager = new SessionManager(
|
||||||
process.env.SERVER_URL as string,
|
process.env.SERVER_URL as string,
|
||||||
process.env.DEFAULT_COMPUTE_CONTEXT as string,
|
process.env.DEFAULT_COMPUTE_CONTEXT as string,
|
||||||
new RequestClient('https://sample.server.com')
|
requestClient
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const getMockSession = () => ({
|
||||||
|
id: ['id', new Date().getTime(), Math.random()].join('-'),
|
||||||
|
state: '',
|
||||||
|
links: [{ rel: 'state', href: '', uri: '', type: '', method: 'GET' }],
|
||||||
|
attributes: {
|
||||||
|
sessionInactiveTimeout: 900
|
||||||
|
},
|
||||||
|
creationTimeStamp: `${new Date(new Date().getTime()).toISOString()}`
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
describe('getVariable', () => {
|
describe('getVariable', () => {
|
||||||
it('should fetch session variable', async () => {
|
it('should fetch session variable', async () => {
|
||||||
const sampleResponse = {
|
const sampleResponse = {
|
||||||
@@ -45,6 +61,30 @@ describe('SessionManager', () => {
|
|||||||
)
|
)
|
||||||
).resolves.toEqual(expectedResponse)
|
).resolves.toEqual(expectedResponse)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should throw an error if GET request failed', async () => {
|
||||||
|
const responseStatus = 500
|
||||||
|
const responseErrorMessage = `The process timed out after 60 seconds. Request failed with status code ${responseStatus}`
|
||||||
|
const response = {
|
||||||
|
status: responseStatus,
|
||||||
|
data: {
|
||||||
|
message: responseErrorMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const testVariable = 'testVariable'
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'get').mockImplementation(() =>
|
||||||
|
Promise.reject({
|
||||||
|
response
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const expectedError = `Error while fetching session variable '${testVariable}'.`
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
sessionManager.getVariable('testId', testVariable)
|
||||||
|
).rejects.toEqual(prefixMessage({ response } as any, expectedError))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('waitForSession', () => {
|
describe('waitForSession', () => {
|
||||||
@@ -135,4 +175,243 @@ describe('SessionManager', () => {
|
|||||||
).resolves.toEqual(customSession.state)
|
).resolves.toEqual(customSession.state)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isSessionValid', () => {
|
||||||
|
const session: Session = getMockSession()
|
||||||
|
|
||||||
|
it('should return false if not a session provided', () => {
|
||||||
|
expect(sessionManager['isSessionValid'](undefined as any)).toEqual(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true if session is not expired', () => {
|
||||||
|
expect(sessionManager['isSessionValid'](session)).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return false if session is expired', () => {
|
||||||
|
session.creationTimeStamp = `${new Date(
|
||||||
|
new Date().getTime() -
|
||||||
|
(session.attributes.sessionInactiveTimeout * 1000 + 1000)
|
||||||
|
).toISOString()}`
|
||||||
|
expect(sessionManager['isSessionValid'](session)).toEqual(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('removeSessionFromPull', () => {
|
||||||
|
it('should remove session from the pull of sessions', () => {
|
||||||
|
const session: Session = getMockSession()
|
||||||
|
const sessions: Session[] = [getMockSession(), session]
|
||||||
|
|
||||||
|
sessionManager['sessions'] = sessions
|
||||||
|
sessionManager['removeSessionFromPull'](session)
|
||||||
|
|
||||||
|
expect(sessionManager['sessions'].length).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('getSession', () => {
|
||||||
|
it('should return session if there is a valid session and create new session', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(sessionManager as any, 'createAndWaitForSession')
|
||||||
|
.mockImplementation(async () => Promise.resolve(getMockSession()))
|
||||||
|
|
||||||
|
const session = getMockSession()
|
||||||
|
sessionManager['sessions'] = [session]
|
||||||
|
|
||||||
|
await expect(sessionManager.getSession()).resolves.toEqual(session)
|
||||||
|
expect(sessionManager['createAndWaitForSession']).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a session and keep one session if there is no sessions available', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(sessionManager as any, 'createAndWaitForSession')
|
||||||
|
.mockImplementation(async () => {
|
||||||
|
const session = getMockSession()
|
||||||
|
sessionManager['sessions'].push(session)
|
||||||
|
|
||||||
|
return Promise.resolve(session)
|
||||||
|
})
|
||||||
|
|
||||||
|
const session = await sessionManager.getSession()
|
||||||
|
|
||||||
|
expect(Object.keys(session)).toEqual(Object.keys(getMockSession()))
|
||||||
|
expect(sessionManager['createAndWaitForSession']).toHaveBeenCalledTimes(2)
|
||||||
|
expect(sessionManager['sessions'].length).toEqual(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.concurrent(
|
||||||
|
'should throw an error if session creation request returned 500',
|
||||||
|
async () => {
|
||||||
|
const sessionCreationStatus = 500
|
||||||
|
const sessionCreationError = `The process initialization for the Compute server with the ID 'ed40398a-ec8a-422b-867a-61493ee8a57f' timed out after 60 seconds. Request failed with status code ${sessionCreationStatus}`
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'post').mockImplementation(() =>
|
||||||
|
Promise.reject({
|
||||||
|
response: {
|
||||||
|
status: sessionCreationStatus,
|
||||||
|
data: {
|
||||||
|
message: sessionCreationError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const contextId = 'testContextId'
|
||||||
|
const context: Context = {
|
||||||
|
name: 'testContext',
|
||||||
|
id: contextId,
|
||||||
|
createdBy: 'createdBy',
|
||||||
|
version: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionManager['currentContext'] = context
|
||||||
|
|
||||||
|
const expectedError = new Error(
|
||||||
|
`Error while creating session. POST request to ${process.env.SERVER_URL}/compute/contexts/${contextId}/sessions failed with status code ${sessionCreationStatus}. ${sessionCreationError}`
|
||||||
|
)
|
||||||
|
|
||||||
|
await expect(sessionManager.getSession()).rejects.toEqual(expectedError)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('clearSession', () => {
|
||||||
|
it('should clear session', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(requestClient, 'delete')
|
||||||
|
.mockImplementation(() =>
|
||||||
|
Promise.resolve({ result: '', etag: '', status: 200 })
|
||||||
|
)
|
||||||
|
|
||||||
|
const sessionToBeCleared = getMockSession()
|
||||||
|
const sessionToStay = getMockSession()
|
||||||
|
|
||||||
|
sessionManager['sessions'] = [sessionToBeCleared, sessionToStay]
|
||||||
|
|
||||||
|
await sessionManager.clearSession(sessionToBeCleared.id)
|
||||||
|
|
||||||
|
expect(sessionManager['sessions']).toEqual([sessionToStay])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if DELETE request failed', async () => {
|
||||||
|
const sessionCreationStatus = 500
|
||||||
|
const sessionDeleteError = `The process timed out after 60 seconds. Request failed with status code ${sessionCreationStatus}`
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'delete').mockImplementation(() =>
|
||||||
|
Promise.reject({
|
||||||
|
response: {
|
||||||
|
status: sessionCreationStatus,
|
||||||
|
data: {
|
||||||
|
message: sessionDeleteError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const session = getMockSession()
|
||||||
|
|
||||||
|
sessionManager['sessions'] = [session]
|
||||||
|
|
||||||
|
const expectedError = `Error while deleting session. DELETE request to /compute/sessions/${session.id} failed with status code ${sessionCreationStatus}. ${sessionDeleteError}`
|
||||||
|
|
||||||
|
await expect(sessionManager.clearSession(session.id)).rejects.toEqual(
|
||||||
|
expectedError
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('waitForCurrentContext', () => {
|
||||||
|
it('should resolve when current context is ready', async () => {
|
||||||
|
sessionManager['settingContext'] = true
|
||||||
|
sessionManager['contextName'] = 'test context'
|
||||||
|
|
||||||
|
await expect(sessionManager['waitForCurrentContext']()).toResolve()
|
||||||
|
expect(sessionManager['settingContext']).toEqual(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('setCurrentContext', () => {
|
||||||
|
it('should set current context', async () => {
|
||||||
|
const contextName = 'test context'
|
||||||
|
const testContext: Context = {
|
||||||
|
name: contextName,
|
||||||
|
id: 'string',
|
||||||
|
createdBy: 'string',
|
||||||
|
version: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'get').mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
result: {
|
||||||
|
items: [testContext]
|
||||||
|
},
|
||||||
|
etag: '',
|
||||||
|
status: 200
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
sessionManager['currentContext'] = null
|
||||||
|
sessionManager['contextName'] = contextName
|
||||||
|
sessionManager['settingContext'] = false
|
||||||
|
|
||||||
|
await expect(sessionManager['setCurrentContext']()).toResolve()
|
||||||
|
expect(sessionManager['currentContext']).toEqual(testContext)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw error if GET request failed', async () => {
|
||||||
|
const responseStatus = 500
|
||||||
|
const responseErrorMessage = `The process timed out after 60 seconds. Request failed with status code ${responseStatus}`
|
||||||
|
const response = {
|
||||||
|
status: responseStatus,
|
||||||
|
data: {
|
||||||
|
message: responseErrorMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'get').mockImplementation(() =>
|
||||||
|
Promise.reject({
|
||||||
|
response
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const expectedError = `Error while getting list of contexts. GET request to https://4gl.io/compute/contexts?limit=10000 failed with status code ${responseStatus}. ${responseErrorMessage}`
|
||||||
|
|
||||||
|
sessionManager['currentContext'] = null
|
||||||
|
|
||||||
|
await expect(sessionManager['setCurrentContext']()).rejects.toEqual(
|
||||||
|
prefixMessage({ response } as any, expectedError)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if current context is not in the list of contexts', async () => {
|
||||||
|
const contextName = 'test context'
|
||||||
|
const testContext: Context = {
|
||||||
|
name: `${contextName} does not exist`,
|
||||||
|
id: 'string',
|
||||||
|
createdBy: 'string',
|
||||||
|
version: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.spyOn(requestClient, 'get').mockImplementation(() => {
|
||||||
|
return Promise.resolve({
|
||||||
|
result: {
|
||||||
|
items: [testContext]
|
||||||
|
},
|
||||||
|
etag: '',
|
||||||
|
status: 200
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
sessionManager['currentContext'] = null
|
||||||
|
sessionManager['contextName'] = contextName
|
||||||
|
sessionManager['settingContext'] = false
|
||||||
|
|
||||||
|
const expectedError = new Error(
|
||||||
|
`The context '${contextName}' was not found on the server https://4gl.io.`
|
||||||
|
)
|
||||||
|
|
||||||
|
await expect(sessionManager['setCurrentContext']()).rejects.toEqual(
|
||||||
|
expectedError
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user