Skip to content

Commit

Permalink
Merge pull request #70 from Gateway-DAO/feat/make-auth-class-public
Browse files Browse the repository at this point in the history
tests: increased test coverage from 91.05% to 95.67%
  • Loading branch information
Siddharth9890 authored Oct 2, 2024
2 parents 34f2ab6 + 347fea8 commit 384c723
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 13 deletions.
4 changes: 2 additions & 2 deletions scripts/generate-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ import { WalletService } from '../services/wallet-service';
signingKey: string;
}\n\n`,
`export enum WalletTypeEnum {
ED25519 = 'ED25519',
SECP256K1 = 'SECP256K1',
Etherum = 'etherum',
Solana = 'solana',
}\n\n`,
`export interface JWTData {
did: string;
Expand Down
4 changes: 2 additions & 2 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export interface WalletSignMessageType {
}

export enum WalletTypeEnum {
ED25519 = 'ED25519',
SECP256K1 = 'SECP256K1',
Etherum = 'etherum',
Solana = 'solana',
}

export interface JWTData {
Expand Down
3 changes: 2 additions & 1 deletion src/helpers/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ export const parameterChecker = (
throw new Error('Need jwt or private key');
}

const urls = ['https://dev.api.gateway.tech'];
const urls = ['https://dev.api.gateway.tech', 'https://api.gateway.tech'];

if (environment === 'dev') return { url: urls[0], mode, value };
else if (environment === 'prod') return { url: urls[1], mode, value };
else throw new Error('No valid url found!. Use sandbox or production url');
};

Expand Down
4 changes: 2 additions & 2 deletions src/services/wallet-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export class WalletService {
walletType?: WalletTypeEnum | undefined;
}) {
this.walletPrivateKey = walletPrivateKey;
this.walletType = walletType ? walletType : WalletTypeEnum.SECP256K1;
this.walletType = walletType ? walletType : WalletTypeEnum.Etherum;
this.wallet =
this.walletType === WalletTypeEnum.SECP256K1
this.walletType === WalletTypeEnum.Etherum
? new EtherumService(this.walletPrivateKey)
: new SolanaService(this.walletPrivateKey);
}
Expand Down
85 changes: 85 additions & 0 deletions test/data-asset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
dataAssetStub,
} from './stubs/data-asset.stub';
import { routes } from '../src/common/routes';
import { toRFC3339 } from '../src/helpers/helper';
import { AccessLevel } from '../src/common/types';

jest.mock('openapi-fetch');

Expand Down Expand Up @@ -86,6 +88,46 @@ describe('Data Assets Test', () => {
expect(id).toEqual(ID);
});

it('should create a file-based data asset with ACL and expiration date', async () => {
mockPost.mockResolvedValue(successMessage({ data: { id: ID } }));

const fileName = 'test.txt';
const fileBuffer = Buffer.from('test content');
const mockACL = { address: '', roles: [AccessLevel.VIEW] };
const mockExpirationDate = new Date('2024-10-01');

mockValidateFileName = jest
.spyOn(validationService, 'validateFileName')
.mockReturnValue({
name: 'test-file',
extension: 'text/plain',
});

const id = await dataAsset.createNonStructured(
fileName,
fileBuffer,
mockACL,
mockExpirationDate,
);

expect(mockValidateFileName).toHaveBeenCalledWith(fileName);
expect(mockPost).toHaveBeenCalledWith('/data-assets', {
body: {},
bodySerializer: expect.any(Function),
});

const formData = new FormData();
formData.append(
'data',
new Blob([fileBuffer], { type: 'text/plain' }),
fileName,
);
formData.append('acl', JSON.stringify(mockACL));
formData.append('expiration_date', toRFC3339(mockExpirationDate));

expect(id).toEqual(ID);
});

it('should throw GTWError on failure for create file data asset', async () => {
mockPost.mockResolvedValue(errorMessage());

Expand Down Expand Up @@ -239,6 +281,49 @@ describe('Data Assets Test', () => {
expect(result).toEqual({ id: ID, name: 'Updated Data Asset' });
});

it('should update a file-based data asset with ACL and expiration date', async () => {
const id = 1;
const fileName = 'test.txt';
const fileBuffer = Buffer.from('test content');
const mockACL = { address: '', roles: [AccessLevel.VIEW] };
const mockExpirationDate = new Date('2024-10-01');

mockValidateFileName = jest
.spyOn(validationService, 'validateFileName')
.mockReturnValue({
name: 'test-file',
extension: 'text/plain',
});

mockPut.mockResolvedValue(successMessage());

const result = await dataAsset.updateNonStructured(
id,
fileName,
fileBuffer,
mockACL,
mockExpirationDate,
);

expect(mockValidateFileName).toHaveBeenCalledWith(fileName);
expect(mockPut).toHaveBeenCalledWith('/data-assets/{id}', {
params: { path: { id } },
body: {},
bodySerializer: expect.any(Function),
});

const formData = new FormData();
formData.append(
'data',
new Blob([fileBuffer], { type: 'text/plain' }),
fileName,
);
formData.append('acl', JSON.stringify(mockACL));
formData.append('expiration_date', toRFC3339(mockExpirationDate));

expect(result).toBeDefined();
});

it('should throw GTWError on failure', async () => {
const id = 1;
const fileName = 'test.txt';
Expand Down
100 changes: 95 additions & 5 deletions test/helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { Auth } from '../src/modules/auth/auth';
import { routes } from '../src/common/routes';

jest.mock('../src/modules/auth/auth');
jest.mock('jsonwebtoken');
jest.mock('jsonwebtoken', () => ({
decode: jest.fn(),
}));

describe('JWT Token Handling', () => {
let config: { client: string; wallet: string };
Expand All @@ -26,9 +28,9 @@ describe('JWT Token Handling', () => {

it('should return existing accessToken when the token is valid', async () => {
jest.mock('../src/helpers/helper', () => ({
...jest.requireActual('../src/helpers/helper'), // preserve other exports
...jest.requireActual('../src/helpers/helper'),
checkJWTTokenExpiration: jest.fn().mockReturnValue(true),
issueJWT: jest.fn(), // Mock issueJWT but don't call it
issueJWT: jest.fn(),
}));

accessToken = 'mockAccessToken';
Expand All @@ -51,14 +53,31 @@ describe('JWT Token Handling', () => {

describe('Utils', () => {
describe('parameterChecker', () => {
it('should return dev URL for dev environment', () => {
expect(parameterChecker('dev', '', 'some-random-hex-key')).toStrictEqual({
beforeEach(() => {
jest.resetAllMocks();
});

it('should return dev URL and privateKey mode for dev environment', () => {
const result = parameterChecker('dev', '', 'some-random-hex-key');
expect(result).toStrictEqual({
mode: 'privateKey',
url: 'https://dev.api.gateway.tech',
value: 'some-random-hex-key',
});
});

it('should throw error if JWT is expired', () => {
const mockExpiredJwt = 'expiredMockJwt';
jest.mock('../src/helpers/helper', () => ({
...jest.requireActual('../src/helpers/helper'),
checkJWTTokenExpiration: jest.fn().mockReturnValue(false),
}));

expect(() => parameterChecker('dev', mockExpiredJwt)).toThrow(
'The provided token is expired or invalid.',
);
});

it('should throw error for invalid environment', () => {
expect(() => parameterChecker('production' as any)).toThrow(
'Need jwt or private key',
Expand All @@ -70,6 +89,10 @@ describe('Utils', () => {
'No url found!.Use either sandbox or production env',
);
});

it('should throw error if neither JWT nor privateKey is provided', () => {
expect(() => parameterChecker('dev')).toThrow('Need jwt or private key');
});
});

describe('AuthMiddleware', () => {
Expand Down Expand Up @@ -153,4 +176,71 @@ describe('Utils', () => {
expect(toRFC3339(date)).toBe('2023-05-15T10:30:00.000Z');
});
});

describe('checkJWTTokenExpiration', () => {
const mockCurrentTime = Math.floor(Date.now() / 1000);

beforeEach(() => {
jest.clearAllMocks();
});

it('should return true if the token is valid and not expired', () => {
const mockToken = 'mockToken';
const mockDecodedToken = {
exp: mockCurrentTime + 3600,
};

(jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken);

const result = checkJWTTokenExpiration(mockToken);
expect(jwt.decode).toHaveBeenCalledWith(mockToken);
expect(result).toBe(true);
});

it('should return false if the token is expired', () => {
const mockToken = 'mockToken';
const mockDecodedToken = {
exp: mockCurrentTime - 100,
};

(jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken);

const result = checkJWTTokenExpiration(mockToken);
expect(jwt.decode).toHaveBeenCalledWith(mockToken);
expect(result).toBe(false);
});

it('should return false if the token does not have an exp field', () => {
const mockToken = 'mockToken';
const mockDecodedToken = {};

(jwt.decode as jest.Mock).mockReturnValue(mockDecodedToken);

const result = checkJWTTokenExpiration(mockToken);
expect(jwt.decode).toHaveBeenCalledWith(mockToken);
expect(result).toBe(true);
});

it('should return false if jwt.decode returns null', () => {
const mockToken = 'mockToken';

(jwt.decode as jest.Mock).mockReturnValue(null);

const result = checkJWTTokenExpiration(mockToken);
expect(jwt.decode).toHaveBeenCalledWith(mockToken);
expect(result).toBe(false);
});

it('should return false if jwt.decode throws an error', () => {
const mockToken = 'mockToken';

(jwt.decode as jest.Mock).mockImplementation(() => {
throw new Error('Error decoding token');
});

const result = checkJWTTokenExpiration(mockToken);
expect(jwt.decode).toHaveBeenCalledWith(mockToken);
expect(result).toBe(false);
});
});
});
1 change: 0 additions & 1 deletion test/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ describe('validateObjectProperties', () => {
it('should throw an error if validation fails', () => {
const obj = { did: 'invalidDID' };

// Spy on the validateDID method and make it throw an error
jest.spyOn(validationService, 'validateDID').mockImplementation(() => {
throw new Error('Invalid DID');
});
Expand Down

0 comments on commit 384c723

Please sign in to comment.