Skip to content

Commit

Permalink
feat: add precheck endpoint for updating workspace storage
Browse files Browse the repository at this point in the history
  • Loading branch information
jzunigax2 committed Nov 19, 2024
1 parent 022290c commit 8a04ecf
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 20 deletions.
43 changes: 43 additions & 0 deletions src/modules/gateway/gateway.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,49 @@ describe('Gateway Controller', () => {
});
});

describe('POST /workspaces/storage/precheck', () => {
const updateWorkspaceStorageDto: UpdateWorkspaceStorageDto = {
ownerId: v4(),
maxSpaceBytes: 1000000,
numberOfSeats: 5,
};

it('When owner passed is not found, then it should throw.', async () => {
jest
.spyOn(gatewayUsecases, 'precheckUpdateWorkspaceStorage')
.mockRejectedValueOnce(new BadRequestException());
await expect(
gatewayController.precheckUpdateWorkspaceStorage(
updateWorkspaceStorageDto,
),
).rejects.toThrow(BadRequestException);
});

it('When workspace is not found, then it should throw.', async () => {
jest
.spyOn(gatewayUsecases, 'precheckUpdateWorkspaceStorage')
.mockRejectedValueOnce(new NotFoundException());
await expect(
gatewayController.precheckUpdateWorkspaceStorage(
updateWorkspaceStorageDto,
),
).rejects.toThrow(NotFoundException);
});

it('When correct data is passed and workspace completed is found, then it works.', async () => {
await gatewayController.precheckUpdateWorkspaceStorage(
updateWorkspaceStorageDto,
);
expect(
gatewayUsecases.precheckUpdateWorkspaceStorage,
).toHaveBeenCalledWith(
updateWorkspaceStorageDto.ownerId,
updateWorkspaceStorageDto.maxSpaceBytes,
updateWorkspaceStorageDto.numberOfSeats,
);
});
});

describe('DELETE /workspaces', () => {
const deleteWorkspaceDto: DeleteWorkspaceDto = {
ownerId: v4(),
Expand Down
17 changes: 17 additions & 0 deletions src/modules/gateway/gateway.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ export class GatewayController {
);
}

@Post('/workspaces/storage/precheck')
@ApiOperation({
summary: 'Precheck for updating a workspace',
})
@ApiBearerAuth('gateway')
@UseGuards(GatewayGuard)
@ApiOkResponse({ description: 'Returns whether the update is possible' })
async precheckUpdateWorkspaceStorage(
@Body() updateWorkspaceStorageDto: UpdateWorkspaceStorageDto,
) {
return this.gatewayUseCases.precheckUpdateWorkspaceStorage(
updateWorkspaceStorageDto.ownerId,
updateWorkspaceStorageDto.maxSpaceBytes,
updateWorkspaceStorageDto.numberOfSeats,
);
}

@Delete('/workspaces')
@ApiOperation({
summary: 'Destroy a workspace',
Expand Down
37 changes: 37 additions & 0 deletions src/modules/gateway/gateway.usecase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,43 @@ describe('GatewayUseCases', () => {
});
});

describe('precheckUpdateWorkspaceStorage', () => {
it('When user is not found, then it should throw', async () => {
jest.spyOn(userRepository, 'findByUuid').mockResolvedValueOnce(null);
await expect(
service.precheckUpdateWorkspaceStorage(v4(), maxSpaceBytes, 4),
).rejects.toThrow(BadRequestException);
});

it('When the workspace is not found, then it should throw', async () => {
jest.spyOn(userRepository, 'findByUuid').mockResolvedValueOnce(owner);
jest.spyOn(workspaceUseCases, 'findOne').mockResolvedValueOnce(null);

await expect(
service.precheckUpdateWorkspaceStorage(owner.uuid, maxSpaceBytes, 4),
).rejects.toThrow(NotFoundException);
});

it('When owner and workspaces are found, then it should call precheckUpdateWorkspaceLimit', async () => {
const owner = newUser();
const workspace = newWorkspace({ owner });
jest.spyOn(userRepository, 'findByUuid').mockResolvedValueOnce(owner);
jest
.spyOn(workspaceUseCases, 'findOne')
.mockResolvedValueOnce(workspace);

await service.precheckUpdateWorkspaceStorage(
owner.uuid,
maxSpaceBytes,
4,
);

expect(
workspaceUseCases.precheckUpdateWorkspaceLimit,
).toHaveBeenCalledWith(workspace, maxSpaceBytes, 4);
});
});

describe('destroyWorkspace', () => {
it('When owner is not found, then it should throw', async () => {
jest.spyOn(userRepository, 'findByUuid').mockResolvedValue(null);
Expand Down
25 changes: 25 additions & 0 deletions src/modules/gateway/gateway.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,31 @@ export class GatewayUseCases {
}
}

async precheckUpdateWorkspaceStorage(
ownerId: string,
maxSpaceBytes: number,
numberOfSeats: number,
): Promise<void> {
const owner = await this.userRepository.findByUuid(ownerId);
if (!owner) {
throw new BadRequestException();
}
const workspace = await this.workspaceUseCases.findOne({
ownerId: owner.uuid,
setupCompleted: true,
});

if (!workspace) {
throw new NotFoundException('Workspace not found');
}

await this.workspaceUseCases.precheckUpdateWorkspaceLimit(
workspace,
maxSpaceBytes,
workspace.numberOfSeats !== numberOfSeats ? numberOfSeats : undefined,
);
}

async destroyWorkspace(ownerId: string): Promise<void> {
const owner = await this.userRepository.findByUuid(ownerId);
if (!owner) {
Expand Down
144 changes: 138 additions & 6 deletions src/modules/workspaces/workspaces.usecase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1764,6 +1764,134 @@ describe('WorkspacesUsecases', () => {
});
});

describe('calculateWorkspaceLimits', () => {
it('When a new limit is specified, calculate spaceDifference', async () => {
const memberCount = 5;
const workspace = newWorkspace({
attributes: {
numberOfSeats: memberCount,
},
});
const currentSpaceLimit = 10000;
const newSpaceLimit = currentSpaceLimit * 2;

jest
.spyOn(workspaceRepository, 'getWorkspaceUsersCount')
.mockResolvedValue(memberCount);
jest
.spyOn(service, 'getWorkspaceNetworkLimit')
.mockResolvedValue(currentSpaceLimit);

const { unusedSpace, spaceDifference } =
await service.calculateWorkspaceLimits(workspace, newSpaceLimit);

expect(unusedSpace).toBe(0);

expect(spaceDifference).toBe(
(newSpaceLimit - currentSpaceLimit) / memberCount,
);
});

it('When workspace is not full return unusedSpace diiferent than 0', async () => {
const memberCount = 5;
const numberOfSeats = 7;
const workspace = newWorkspace({
attributes: {
numberOfSeats,
},
});
const spacePerUser = 10000;
const currentSpaceLimit = spacePerUser * numberOfSeats;
const newSpaceLimit = currentSpaceLimit * 2;

jest
.spyOn(workspaceRepository, 'getWorkspaceUsersCount')
.mockResolvedValue(memberCount);
jest
.spyOn(service, 'getWorkspaceNetworkLimit')
.mockResolvedValue(currentSpaceLimit);

const { unusedSpace, spaceDifference } =
await service.calculateWorkspaceLimits(workspace, newSpaceLimit);

expect(unusedSpace).toBe(spacePerUser * (numberOfSeats - memberCount));

expect(spaceDifference).toBe(spacePerUser * 2 - spacePerUser);
});

it('When a different numberOfSeats is specified, spacedifference should vary', async () => {
const memberCount = 5;
const numberOfSeats = memberCount;
const newNumberOfSeats = numberOfSeats * 2;
const workspace = newWorkspace({
attributes: {
numberOfSeats,
},
});
const spacePerUser = 10000;
const currentSpaceLimit = spacePerUser * numberOfSeats;
const newSpaceLimit = spacePerUser * newNumberOfSeats;

jest
.spyOn(workspaceRepository, 'getWorkspaceUsersCount')
.mockResolvedValue(memberCount);
jest
.spyOn(service, 'getWorkspaceNetworkLimit')
.mockResolvedValue(currentSpaceLimit);

const { unusedSpace, spaceDifference } =
await service.calculateWorkspaceLimits(
workspace,
newSpaceLimit,
newNumberOfSeats,
);

expect(unusedSpace).toBe(spacePerUser * (newNumberOfSeats - memberCount));

expect(spaceDifference).toBe(0);
});
});

describe('precheckUpdateWorkspaceLimit', () => {
it('should throw BadRequestException if unused space is less than owner limit', async () => {
const workspace = newWorkspace();
const newWorkspaceSpaceLimit = 100;
const newNumberOfSeats = 10;

jest.spyOn(service, 'getOwnerAvailableSpace').mockResolvedValue(50);
jest
.spyOn(service, 'calculateWorkspaceLimits')
.mockResolvedValue({ unusedSpace: 40, spaceDifference: 0 });

await expect(
service.precheckUpdateWorkspaceLimit(
workspace,
newWorkspaceSpaceLimit,
newNumberOfSeats,
),
).rejects.toThrow(BadRequestException);
});

it('should not throw an exception if unused space is greater than or equal to owner limit', async () => {
const workspace = newWorkspace();
const newWorkspaceSpaceLimit = 100;
const newNumberOfSeats = 10;

jest.spyOn(service, 'getOwnerAvailableSpace').mockResolvedValue(50);
jest
.spyOn(service, 'calculateWorkspaceLimits')
.mockResolvedValue({ unusedSpace: 60, spaceDifference: 10 });

await expect(
service.precheckUpdateWorkspaceLimit(
workspace,
newWorkspaceSpaceLimit,
newNumberOfSeats,
),
).resolves.not.toThrow();
});
});

describe('updateWorkspaceLimit', () => {
it('When workspace does not exist, then it should throw', async () => {
jest.spyOn(workspaceRepository, 'findById').mockResolvedValue(null);
Expand Down Expand Up @@ -1805,9 +1933,6 @@ describe('WorkspacesUsecases', () => {
jest
.spyOn(userRepository, 'findByUuid')
.mockResolvedValue(workspaceNetworkUser);
jest
.spyOn(service, 'getWorkspaceNetworkLimit')
.mockResolvedValue(currentSpaceLimit);
jest
.spyOn(workspaceRepository, 'findWorkspaceUsers')
.mockResolvedValue(workspaceUsers);
Expand All @@ -1822,6 +1947,11 @@ describe('WorkspacesUsecases', () => {
currentSpaceLimit -
(newSpacePerUser - oldSpacePerUser) * workspaceUsers.length;

jest.spyOn(service, 'calculateWorkspaceLimits').mockResolvedValue({
unusedSpace,
spaceDifference: newSpacePerUser - oldSpacePerUser,
});

await service.updateWorkspaceLimit(workspace.id, newSpaceLimit);

expect(networkService.setStorage).toHaveBeenCalledWith(
Expand Down Expand Up @@ -1870,9 +2000,6 @@ describe('WorkspacesUsecases', () => {
jest
.spyOn(userRepository, 'findByUuid')
.mockResolvedValue(workspaceNetworkUser);
jest
.spyOn(service, 'getWorkspaceNetworkLimit')
.mockResolvedValue(currentSpaceLimit);
jest
.spyOn(workspaceRepository, 'findWorkspaceUsers')
.mockResolvedValue(workspaceUsers);
Expand All @@ -1887,6 +2014,11 @@ describe('WorkspacesUsecases', () => {
currentSpaceLimit -
(newSpacePerUser - oldSpacePerUser) * workspaceUsers.length;

jest.spyOn(service, 'calculateWorkspaceLimits').mockResolvedValue({
unusedSpace,
spaceDifference: newSpacePerUser - oldSpacePerUser,
});

await service.updateWorkspaceLimit(
workspace.id,
newSpaceLimit,
Expand Down
Loading

0 comments on commit 8a04ecf

Please sign in to comment.