From 4db8683bd68e5b906c9df074fcd819bd3f5a439d Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Tue, 1 Oct 2024 09:56:46 +0000 Subject: [PATCH] test(access-token): write model tests --- .../__snapshots__/access-token.test.js.snap | 41 +++++++++ packages/backend/src/models/access-token.js | 15 ++-- .../backend/src/models/access-token.test.js | 84 +++++++++++++++++++ 3 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 packages/backend/src/models/__snapshots__/access-token.test.js.snap create mode 100644 packages/backend/src/models/access-token.test.js diff --git a/packages/backend/src/models/__snapshots__/access-token.test.js.snap b/packages/backend/src/models/__snapshots__/access-token.test.js.snap new file mode 100644 index 00000000..77f8ab95 --- /dev/null +++ b/packages/backend/src/models/__snapshots__/access-token.test.js.snap @@ -0,0 +1,41 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`AccessToken model > jsonSchema should have correct validations 1`] = ` +{ + "properties": { + "expiresIn": { + "type": "integer", + }, + "id": { + "format": "uuid", + "type": "string", + }, + "revokedAt": { + "format": "date-time", + "type": [ + "string", + "null", + ], + }, + "samlSessionId": { + "type": [ + "string", + "null", + ], + }, + "token": { + "minLength": 32, + "type": "string", + }, + "userId": { + "format": "uuid", + "type": "string", + }, + }, + "required": [ + "token", + "expiresIn", + ], + "type": "object", +} +`; diff --git a/packages/backend/src/models/access-token.js b/packages/backend/src/models/access-token.js index 7fba0cb8..912e6ac5 100644 --- a/packages/backend/src/models/access-token.js +++ b/packages/backend/src/models/access-token.js @@ -34,24 +34,25 @@ class AccessToken extends Base { return; } - const user = await this - .$relatedQuery('user'); + const user = await this.$relatedQuery('user'); - const firstIdentity = await user - .$relatedQuery('identities') - .first(); + const firstIdentity = await user.$relatedQuery('identities').first(); const samlAuthProvider = await firstIdentity .$relatedQuery('samlAuthProvider') .throwIfNotFound(); - const response = await samlAuthProvider.terminateRemoteSession(this.samlSessionId); + const response = await samlAuthProvider.terminateRemoteSession( + this.samlSessionId + ); return response; } async revoke() { - const response = await this.$query().patch({ revokedAt: new Date().toISOString() }); + const response = await this.$query().patch({ + revokedAt: new Date().toISOString(), + }); try { await this.terminateRemoteSamlSession(); diff --git a/packages/backend/src/models/access-token.test.js b/packages/backend/src/models/access-token.test.js new file mode 100644 index 00000000..bdfedf27 --- /dev/null +++ b/packages/backend/src/models/access-token.test.js @@ -0,0 +1,84 @@ +import { describe, it, expect, vi } from 'vitest'; +import AccessToken from './access-token.js'; +import User from './user.js'; +import Base from './base.js'; +import SamlAuthProvider from './saml-auth-provider.ee.js'; +import { createAccessToken } from '../../test/factories/access-token.js'; +import { createUser } from '../../test/factories/user.js'; +import { createIdentity } from '../../test/factories/identity.js'; + +describe('AccessToken model', () => { + it('tableName should return correct name', () => { + expect(AccessToken.tableName).toBe('access_tokens'); + }); + + it('jsonSchema should have correct validations', () => { + expect(AccessToken.jsonSchema).toMatchSnapshot(); + }); + + it('relationMappings should return correct associations', () => { + const relationMappings = AccessToken.relationMappings(); + + const expectedRelations = { + user: { + relation: Base.BelongsToOneRelation, + modelClass: User, + join: { + from: 'access_tokens.user_id', + to: 'users.id', + }, + }, + }; + + expect(relationMappings).toStrictEqual(expectedRelations); + }); + + it('revoke should set revokedAt and terminate remote SAML session', async () => { + const accessToken = await createAccessToken(); + + const terminateRemoteSamlSessionSpy = vi + .spyOn(accessToken, 'terminateRemoteSamlSession') + .mockImplementation(() => {}); + + await accessToken.revoke(); + + expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledOnce(); + expect(accessToken.revokedAt).not.toBeUndefined(); + }); + + describe('terminateRemoteSamlSession', () => { + it('should terminate remote SAML session when exists', async () => { + const user = await createUser(); + const accessToken = await createAccessToken({ + userId: user.id, + samlSessionId: 'random-remote-session-id', + }); + await createIdentity({ userId: user.id }); + + const terminateRemoteSamlSessionSpy = vi + .spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession') + .mockImplementation(() => {}); + + await accessToken.terminateRemoteSamlSession(); + + expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledWith( + accessToken.samlSessionId + ); + }); + + it(`should return undefined when remote SALM session doesn't exist`, async () => { + const user = await createUser(); + const accessToken = await createAccessToken({ userId: user.id }); + await createIdentity({ userId: user.id }); + + const terminateRemoteSamlSessionSpy = vi + .spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession') + .mockImplementation(() => {}); + + const expected = await accessToken.terminateRemoteSamlSession(); + + expect(terminateRemoteSamlSessionSpy).not.toHaveBeenCalledOnce(); + expect(expected).toBeUndefined(); + }); + }); +});