mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-13 07:00:06 +00:00
feat(session-manager): refactored and covered with tests
This commit is contained in:
@@ -3,10 +3,12 @@ import { RequestClient } from '../request/RequestClient'
|
||||
import * as dotenv from 'dotenv'
|
||||
import axios from 'axios'
|
||||
import { Logger, LogLevel } from '@sasjs/utils'
|
||||
import { Session } from '../types'
|
||||
import { prefixMessage } from '@sasjs/utils/error'
|
||||
import { Session, Context } from '../types'
|
||||
|
||||
jest.mock('axios')
|
||||
const mockedAxios = axios as jest.Mocked<typeof axios>
|
||||
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||
|
||||
describe('SessionManager', () => {
|
||||
dotenv.config()
|
||||
@@ -14,9 +16,23 @@ describe('SessionManager', () => {
|
||||
const sessionManager = new SessionManager(
|
||||
process.env.SERVER_URL 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', () => {
|
||||
it('should fetch session variable', async () => {
|
||||
const sampleResponse = {
|
||||
@@ -45,6 +61,30 @@ describe('SessionManager', () => {
|
||||
)
|
||||
).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', () => {
|
||||
@@ -135,4 +175,243 @@ describe('SessionManager', () => {
|
||||
).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