Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for certain sync features #228

Merged
merged 5 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ apiRouter.get('/', (_req, res) => {
authMode: state.authMode,
gitRev: state.gitRev,
name: appName,
nodeVersion: appVersion,
nodeVersion: process.version,
privacyMask: config.has('server.privacyMask'),
version: process.env.npm_package_version
version: appVersion
},
endpoints: ['/api/v1'],
versions: [1]
Expand Down
51 changes: 46 additions & 5 deletions app/tests/unit/components/utils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const Problem = require('api-problem');
// Mock config library - @see {@link https://stackoverflow.com/a/64819698}
jest.mock('config');

const DEFAULTREGION = 'us-east-1'; // Need to specify valid AWS region or it'll explode ('us-east-1' is default, 'ca-central-1' for Canada)
// Need to specify valid AWS region or it'll explode ('us-east-1' is default, 'ca-central-1' for Canada)
const DEFAULTREGION = 'us-east-1';

beforeEach(() => {
jest.resetAllMocks();
Expand Down Expand Up @@ -246,7 +247,9 @@ describe('getCurrentSubject', () => {
expect(getCurrentTokenClaimSpy).toHaveBeenCalledWith(currentUser, 'sub', undefined);
});

it.each([undefined, null, '', [], {}])('should call getCurrentTokenClaim correctly given %j and defaultValue \'default\'', (currentUser) => {
it.each(
[undefined, null, '', [], {}]
)('should call getCurrentTokenClaim correctly given %j and defaultValue \'default\'', (currentUser) => {
const defaultValue = 'default';
utils.getCurrentSubject(currentUser, defaultValue);

Expand Down Expand Up @@ -472,15 +475,21 @@ describe('mixedQueryToArray', () => {
});

it('should return an array with the appropriate set when there are multiples', () => {
expect(utils.mixedQueryToArray('there,are,duplicates,here,yes,here,there,is,here')).toEqual(['there', 'are', 'duplicates', 'here', 'yes', 'is']);
expect(utils.mixedQueryToArray('there,are,duplicates,here,yes,here,there,is,here')).toEqual(
['there', 'are', 'duplicates', 'here', 'yes', 'is']
);
});

it('should return an array with the appropriate set when there are multiples and spaces', () => {
expect(utils.mixedQueryToArray('there, are, duplicates, here ,yes ,here ,there,is,here ')).toEqual(['there', 'are', 'duplicates', 'here', 'yes', 'is']);
expect(utils.mixedQueryToArray('there, are, duplicates, here ,yes ,here ,there,is,here ')).toEqual(
['there', 'are', 'duplicates', 'here', 'yes', 'is']
);
});

it('should return an array with the appropriate set when there are multiples and spaces', () => {
expect(utils.mixedQueryToArray(['there', ' are', ' duplicates', ' here ', 'yes ', 'here ', 'there', 'is', 'here '])).toEqual(['there', 'are', 'duplicates', 'here', 'yes', 'is']);
expect(utils.mixedQueryToArray(
['there', ' are', ' duplicates', ' here ', 'yes ', 'here ', 'there', 'is', 'here ']
)).toEqual(['there', 'are', 'duplicates', 'here', 'yes', 'is']);
});
});

Expand Down Expand Up @@ -575,3 +584,35 @@ describe('toLowerKeys', () => {
expect(utils.toLowerKeys(value)).toEqual(expected);
});
});

describe('getUniqueObjects', () => {
const testObj1 = {key1: 'test1', val1: 'val11', val2: 'val21'};
const testObj2 = {key1: 'test2', val1: 'val12', val2: 'val22'};
const testObj3 = {key1: 'test3', val1: 'val13', val2: 'val23'};
const testObj4 = {key1: 'test4', val1: 'val14', val2: 'val24'};
const testObj5 = {key1: 'test4', val1: 'val15', val2: 'val25'};

it('return all input objects', () => {
expect(utils.getUniqueObjects([
testObj1, testObj2, testObj3, testObj4
], 'key1')).toMatchObject([
testObj1, testObj2, testObj3, testObj4
]);
});

it('filter for unique keys', () => {
expect(utils.getUniqueObjects([
testObj2, testObj3, testObj4, testObj5
], 'key1')).toMatchObject([
testObj2, testObj3, testObj5
]);
});

it('should return the last object entered with duplicate key', () => {
expect(utils.getUniqueObjects([
testObj5, testObj4,
], 'key1')).toMatchObject([
testObj4
]);
});
});
9 changes: 8 additions & 1 deletion app/tests/unit/controllers/object.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ const { MAXCOPYOBJECTLENGTH, MetadataDirective, TaggingDirective } = require('..
const utils = require('../../../src/db/models/utils');

const controller = require('../../../src/controllers/object');
const { storageService, objectService, metadataService, tagService, versionService, userService } = require('../../../src/services');
const {
storageService,
objectService,
metadataService,
tagService,
versionService,
userService
} = require('../../../src/services');

const mockResponse = () => {
const res = {};
Expand Down
13 changes: 11 additions & 2 deletions app/tests/unit/controllers/objectPermission.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ describe('searchPermissions', () => {
const res = mockResponse();
await controller.searchPermissions(req, res, next);
expect(searchPermissionsSpy).toHaveBeenCalledTimes(1);
expect(searchPermissionsSpy).toHaveBeenCalledWith({ bucketId: [req.query.bucketId], objId: [req.query.objectId], userId: [req.query.userId], permCode: [req.query.permCode] });
expect(searchPermissionsSpy).toHaveBeenCalledWith({
bucketId: [req.query.bucketId],
objId: [req.query.objectId],
userId: [req.query.userId],
permCode: [req.query.permCode]
});
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith([]);
expect(next).toHaveBeenCalledTimes(0);
Expand Down Expand Up @@ -70,7 +75,11 @@ describe('listPermissions', () => {
const res = mockResponse();
await controller.listPermissions(req, res, next);
expect(searchPermissionsSpy).toHaveBeenCalledTimes(1);
expect(searchPermissionsSpy).toHaveBeenCalledWith({ objId: req.params.objectId, userId: [req.query.userId], permCode: [req.query.permCode] });
expect(searchPermissionsSpy).toHaveBeenCalledWith({
objId: req.params.objectId,
userId: [req.query.userId],
permCode: [req.query.permCode]
});
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith({ res: 123 });
expect(next).toHaveBeenCalledTimes(0);
Expand Down
7 changes: 6 additions & 1 deletion app/tests/unit/middleware/authorization.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
const { NIL: SYSTEM_USER } = require('uuid');

const mw = require('../../../src/middleware/authorization');
const { bucketPermissionService, objectService, objectPermissionService, userService } = require('../../../src/services');
const {
bucketPermissionService,
objectService,
objectPermissionService,
userService
} = require('../../../src/services');
const { AuthMode, AuthType, Permissions } = require('../../../src/components/constants');
const utils = require('../../../src/components/utils');

Expand Down
158 changes: 103 additions & 55 deletions app/tests/unit/services/storage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ const service = require('../../../src/services/storage');
const utils = require('../../../src/components/utils');
const { MetadataDirective, TaggingDirective } = require('../../../src/components/constants');

const DEFAULTREGION = 'us-east-1'; // Need to specify valid AWS region or it'll explode ('us-east-1' is default, 'ca-central-1' for Canada)
// Need to specify valid AWS region or it'll explode ('us-east-1' is default, 'ca-central-1' for Canada)
const DEFAULTREGION = 'us-east-1';

const bucket = 'bucket';
const key = 'filePath';
const defaultTempExpiresIn = parseInt(config.get('server.defaultTempExpiresIn'), 10);
Expand Down Expand Up @@ -456,8 +458,14 @@ describe('listAllObjects', () => {

it('should call listObjectsV2 multiple times and return an array of precise path objects', async () => {
const continueToken = 'token';
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/foo' }], IsTruncated: true, NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/bar' }], IsTruncated: false });
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/foo' }],
IsTruncated: true,
NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/bar' }],
IsTruncated: false
});

const result = await service.listAllObjects();

Expand All @@ -482,8 +490,14 @@ describe('listAllObjects', () => {

it('should call listObjectsV2 multiple times and return an array of all path objects', async () => {
const continueToken = 'token';
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/test/foo' }], IsTruncated: true, NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/test/bar' }], IsTruncated: false });
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/test/foo' }],
IsTruncated: true,
NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/test/bar' }],
IsTruncated: false
});

const result = await service.listAllObjects({ precisePath: false });

Expand All @@ -506,34 +520,43 @@ describe('listAllObjects', () => {
}));
});

it('should call listObjectsV2 multiple times with the right bucketId and filePath, returning an array of objects', async () => {
const continueToken = 'token';
const customPath = 'filePath/test';
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/test/foo' }], IsTruncated: true, NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({ Contents: [{ Key: 'filePath/test/bar' }], IsTruncated: false });

const result = await service.listAllObjects({ filePath: customPath, bucketId: bucket });

expect(result).toBeTruthy();
expect(Array.isArray(result)).toBeTruthy();
expect(result).toHaveLength(2);
expect(result).toEqual(expect.arrayContaining([
{ Key: 'filePath/test/foo' },
{ Key: 'filePath/test/bar' }
]));
expect(utils.getBucket).toHaveBeenCalledTimes(0);
expect(utils.isAtPath).toHaveBeenCalledTimes(2);
expect(listObjectsV2Mock).toHaveBeenCalledTimes(2);
expect(listObjectsV2Mock).toHaveBeenNthCalledWith(1, expect.objectContaining({
filePath: customPath,
bucketId: bucket
}));
expect(listObjectsV2Mock).toHaveBeenNthCalledWith(2, expect.objectContaining({
filePath: customPath,
continuationToken: continueToken,
bucketId: bucket
}));
});
it(
'should call listObjectsV2 multiple times with the right bucketId and filePath, returning an array of objects',
async () => {
const continueToken = 'token';
const customPath = 'filePath/test';
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/test/foo' }],
IsTruncated: true,
NextContinuationToken: continueToken });
listObjectsV2Mock.mockResolvedValueOnce({
Contents: [{ Key: 'filePath/test/bar' }],
IsTruncated: false
});

const result = await service.listAllObjects({ filePath: customPath, bucketId: bucket });

expect(result).toBeTruthy();
expect(Array.isArray(result)).toBeTruthy();
expect(result).toHaveLength(2);
expect(result).toEqual(expect.arrayContaining([
{ Key: 'filePath/test/foo' },
{ Key: 'filePath/test/bar' }
]));
expect(utils.getBucket).toHaveBeenCalledTimes(0);
expect(utils.isAtPath).toHaveBeenCalledTimes(2);
expect(listObjectsV2Mock).toHaveBeenCalledTimes(2);
expect(listObjectsV2Mock).toHaveBeenNthCalledWith(1, expect.objectContaining({
filePath: customPath,
bucketId: bucket
}));
expect(listObjectsV2Mock).toHaveBeenNthCalledWith(2, expect.objectContaining({
filePath: customPath,
continuationToken: continueToken,
bucketId: bucket
}));
}
);
});

describe('listAllObjectVersions', () => {
Expand Down Expand Up @@ -589,8 +612,14 @@ describe('listAllObjectVersions', () => {

it('should call listObjectVersion multiple times and return precise path objects', async () => {
const nextKeyMarker = 'token';
listObjectVersionMock.mockResolvedValueOnce({ DeleteMarkers: [{ Key: 'filePath/foo' }], IsTruncated: true, NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({ Versions: [{ Key: 'filePath/bar' }], IsTruncated: false });
listObjectVersionMock.mockResolvedValueOnce({
DeleteMarkers: [{ Key: 'filePath/foo' }],
IsTruncated: true,
NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({
Versions: [{ Key: 'filePath/bar' }],
IsTruncated: false
});

const result = await service.listAllObjectVersions({ filePath: 'filePath' });

Expand Down Expand Up @@ -619,8 +648,14 @@ describe('listAllObjectVersions', () => {

it('should call listObjectVersion multiple times and return all path objects', async () => {
const nextKeyMarker = 'token';
listObjectVersionMock.mockResolvedValueOnce({ DeleteMarkers: [{ Key: 'filePath/test/foo' }], IsTruncated: true, NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({ Versions: [{ Key: 'filePath/test/bar' }], IsTruncated: false });
listObjectVersionMock.mockResolvedValueOnce({
DeleteMarkers: [{ Key: 'filePath/test/foo' }],
IsTruncated: true,
NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({
Versions: [{ Key: 'filePath/test/bar' }],
IsTruncated: false
});

const result = await service.listAllObjectVersions({ filePath: 'filePath', precisePath: false });

Expand Down Expand Up @@ -649,10 +684,20 @@ describe('listAllObjectVersions', () => {

it('should call listObjectVersion multiple times and return all latest path objects', async () => {
const nextKeyMarker = 'token';
listObjectVersionMock.mockResolvedValueOnce({ DeleteMarkers: [{ Key: 'filePath/test/foo', IsLatest: true }], IsTruncated: true, NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({ Versions: [{ Key: 'filePath/test/bar', IsLatest: false }], IsTruncated: false });
listObjectVersionMock.mockResolvedValueOnce({
DeleteMarkers: [{ Key: 'filePath/test/foo', IsLatest: true }],
IsTruncated: true,
NextKeyMarker: nextKeyMarker });
listObjectVersionMock.mockResolvedValueOnce({
Versions: [{ Key: 'filePath/test/bar', IsLatest: false }],
IsTruncated: false
});

const result = await service.listAllObjectVersions({ filePath: 'filePath', precisePath: false, filterLatest: true });
const result = await service.listAllObjectVersions({
filePath: 'filePath',
precisePath: false,
filterLatest: true
});

expect(result).toBeTruthy();
expect(Array.isArray(result.DeleteMarkers)).toBeTruthy();
Expand Down Expand Up @@ -941,21 +986,24 @@ describe('readSignedUrl', () => {
presignUrlMock.mockRestore();
});

it('should call presignUrl with a get object command for the latest object and default expiration and bucketId', async () => {
const filePath = 'filePath';
const bucketId = 'abc';
const result = await service.readSignedUrl({ filePath, bucketId: bucketId });

expect(result).toBeTruthy();
expect(utils.getBucket).toHaveBeenCalledTimes(1);
expect(presignUrlMock).toHaveBeenCalledTimes(1);
expect(presignUrlMock).toHaveBeenCalledWith(expect.objectContaining({
input: {
Bucket: bucket,
Key: filePath
}
}), defaultTempExpiresIn, bucketId);
});
it(
'should call presignUrl with a get object command for the latest object and default expiration and bucketId',
async () => {
const filePath = 'filePath';
const bucketId = 'abc';
const result = await service.readSignedUrl({ filePath, bucketId: bucketId });

expect(result).toBeTruthy();
expect(utils.getBucket).toHaveBeenCalledTimes(1);
expect(presignUrlMock).toHaveBeenCalledTimes(1);
expect(presignUrlMock).toHaveBeenCalledWith(expect.objectContaining({
input: {
Bucket: bucket,
Key: filePath
}
}), defaultTempExpiresIn, bucketId);
}
);

it('should call presignUrl with a get object command for a specific version and default expiration', async () => {
const filePath = 'filePath';
Expand Down
Loading
Loading