Skip to content

Commit

Permalink
chore: added test cases for usage
Browse files Browse the repository at this point in the history
  • Loading branch information
apsantiso committed Dec 9, 2024
1 parent bce6245 commit b3100c6
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 45 deletions.
275 changes: 275 additions & 0 deletions src/modules/usage/usage.usecase.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
import { Test, TestingModule } from '@nestjs/testing';
import { createMock } from '@golevelup/ts-jest';
import { UsageUseCases } from './usage.usecase';
import { SequelizeUsageRepository } from './usage.repository';
import { SequelizeFileRepository } from '../file/file.repository';
import { Usage, UsageType } from './usage.domain';
import { newFile, newUsage, newUser } from '../../../test/fixtures';
import { v4 } from 'uuid';

describe('UsageUseCases', () => {
let usageUseCases: UsageUseCases;
let usageRepository: SequelizeUsageRepository;
let fileRepository: SequelizeFileRepository;

const userMocked = newUser({
attributes: { uuid: v4(), id: 1, email: '[email protected]' },
});

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsageUseCases],
})
.useMocker(createMock)
.compile();

usageUseCases = module.get<UsageUseCases>(UsageUseCases);
usageRepository = module.get<SequelizeUsageRepository>(
SequelizeUsageRepository,
);
fileRepository = module.get<SequelizeFileRepository>(
SequelizeFileRepository,
);
});

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

describe('getUserUsage', () => {
it('When user has existing usage, it calculates usage correctly', async () => {
const existingUsage = newUsage({
attributes: {
delta: 100,
type: UsageType.Monthly,
userId: userMocked.uuid,
},
});

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(existingUsage);
jest
.spyOn(fileRepository, 'sumFileSizesSinceDate')
.mockResolvedValueOnce(200);
jest.spyOn(usageRepository, 'getUserUsage').mockResolvedValueOnce({
total_monthly_delta: 300,
total_yearly_delta: 500,
});

const result = await usageUseCases.getUserUsage(userMocked);

expect(result).toEqual({ drive: 1000, id: userMocked.email });
});

it('When user has no existing usage, it creates first monhtly usage and calculates correctly', async () => {
const firstMonthlyUsage = newUsage({
attributes: {
delta: 0,
type: UsageType.Monthly,
userId: userMocked.uuid,
},
});

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(null);
jest
.spyOn(usageRepository, 'addFirstMonthlyUsage')
.mockResolvedValueOnce(firstMonthlyUsage);
jest
.spyOn(fileRepository, 'sumFileSizesSinceDate')
.mockResolvedValueOnce(100);
jest.spyOn(usageRepository, 'getUserUsage').mockResolvedValueOnce({
total_monthly_delta: 200,
total_yearly_delta: 300,
});

const result = await usageUseCases.getUserUsage(userMocked);

expect(result).toEqual({ drive: 600, id: userMocked.email });
expect(usageRepository.addFirstMonthlyUsage).toHaveBeenCalledWith(
userMocked.uuid,
);
});

it('When user has yearly usage, it calculates usage correctly', async () => {
const yearlyUsage = newUsage({
attributes: {
delta: 500,
type: UsageType.Yearly,
userId: userMocked.uuid,
period: new Date(),
},
});

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(yearlyUsage);
jest
.spyOn(fileRepository, 'sumFileSizesSinceDate')
.mockResolvedValueOnce(400);
jest.spyOn(usageRepository, 'getUserUsage').mockResolvedValueOnce({
total_monthly_delta: 200,
total_yearly_delta: 500,
});

const result = await usageUseCases.getUserUsage(userMocked);

expect(result).toEqual({ drive: 1100, id: userMocked.email });
});

it('When user has monthly usage, it calculates usage correctly and calculates file changes since next day', async () => {
const monthlyUsage = newUsage({
attributes: {
delta: 200,
type: UsageType.Monthly,
userId: userMocked.uuid,
period: new Date('2023-01-01T00:00:00Z'),
},
});
const expectedCalculateDate = new Date('2023-01-02T00:00:00Z');

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(monthlyUsage);
const sumFileSizesSinceSpy = jest
.spyOn(fileRepository, 'sumFileSizesSinceDate')
.mockResolvedValueOnce(300);
jest.spyOn(usageRepository, 'getUserUsage').mockResolvedValueOnce({
total_monthly_delta: 200,
total_yearly_delta: 500,
});

const result = await usageUseCases.getUserUsage(userMocked);

expect(result).toEqual({ drive: 1000, id: userMocked.email });
expect(sumFileSizesSinceSpy).toHaveBeenCalledWith(
userMocked.id,
expectedCalculateDate,
);
});

it('When user has yearly usage, it calculates usage correctly and calculates file changes since next year', async () => {
const yearlyUsage = newUsage({
attributes: {
delta: 500,
type: UsageType.Yearly,
userId: userMocked.uuid,
period: new Date('2023-01-01T00:00:00Z'),
},
});
const expectedCalculateDate = new Date('2024-01-01T00:00:00Z');

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(yearlyUsage);
const sumFileSizesSinceSpy = jest
.spyOn(fileRepository, 'sumFileSizesSinceDate')
.mockResolvedValueOnce(400);
jest.spyOn(usageRepository, 'getUserUsage').mockResolvedValueOnce({
total_monthly_delta: 200,
total_yearly_delta: 500,
});

const result = await usageUseCases.getUserUsage(userMocked);

expect(result).toEqual({ drive: 1100, id: userMocked.email });
expect(sumFileSizesSinceSpy).toHaveBeenCalledWith(
userMocked.id,
expectedCalculateDate,
);
});
});

describe('createDailyUsage', () => {
it('When daily usage is created, it should return the created usage', async () => {
const dailyUsage = newUsage({
attributes: {
delta: 50,
type: UsageType.Daily,
userId: userMocked.uuid,
},
});

jest.spyOn(usageRepository, 'create').mockResolvedValueOnce(dailyUsage);

const result = await usageUseCases.createDailyUsage(
userMocked.uuid,
new Date(),
50,
);

expect(result).toEqual(dailyUsage);
});
});

describe('addDailyUsageChangeOnFileSizeChange', () => {
it('When file size changes and delta is non-zero, it creates a daily usage', async () => {
const oldFile = newFile({ attributes: { size: BigInt(100) } });
const fileChanged = newFile({ attributes: { size: BigInt(200) } });
const dailyUsage = newUsage({
attributes: {
delta: 100,
type: UsageType.Daily,
userId: userMocked.uuid,
},
});
const monthlyUsage = newUsage({
attributes: {
delta: 100,
type: UsageType.Monthly,
userId: userMocked.uuid,
},
});

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(monthlyUsage);
jest
.spyOn(usageUseCases, 'createDailyUsage')
.mockResolvedValueOnce(dailyUsage);

await usageUseCases.addDailyUsageChangeOnFileSizeChange(
userMocked,
oldFile,
fileChanged,
);

expect(usageUseCases.createDailyUsage).toHaveBeenCalledWith(
userMocked.uuid,
expect.any(Date),
100,
);
});

it('When file size does not change, it should not create daily usage', async () => {
const oldFile = newFile({ attributes: { size: BigInt(100) } });
const fileChanged = newFile({ attributes: { size: BigInt(100) } });

jest
.spyOn(usageRepository, 'getMostRecentMonthlyOrYearlyUsage')
.mockResolvedValueOnce(
Usage.build({
id: v4(),
userId: userMocked.uuid,
delta: 0,
period: new Date(),
type: UsageType.Daily,
createdAt: new Date(),
updatedAt: new Date(),
}),
);
jest.spyOn(usageUseCases, 'createDailyUsage');

const result = await usageUseCases.addDailyUsageChangeOnFileSizeChange(
userMocked,
oldFile,
fileChanged,
);

expect(result).toBeNull();
expect(usageUseCases.createDailyUsage).not.toHaveBeenCalled();
});
});
});
45 changes: 0 additions & 45 deletions src/modules/usage/usage.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,51 +69,6 @@ export class UsageUseCases {
return createdDailyUsage;
}

/* async addDailyUsageChangeOnFileSizeChange(
user: User,
oldFileData: File,
newFileData: File,
) {
const mostRecentDailyUsage = await this.usageRepository.getUsage(
{
type: UsageType.Daily,
userId: user.uuid,
},
[['createdAt', 'DESC']],
);
let calculateChangesSince: Date = mostRecentDailyUsage?.createdAt;
const now = new Date();
if (
!calculateChangesSince ||
new Date(calculateChangesSince).toDateString() !== now.toDateString()
) {
calculateChangesSince = new Date(now);
calculateChangesSince.setUTCHours(0, 0, 0, 0);
}
const totalStorageChanged = await this.fileRepository.sumFileSizesSinceDate(
user.id,
calculateChangesSince,
);
if (newFileData.createdAt.toDateString() !== now.toDateString()) {
const delta =
Number(newFileData.size) -
Number(oldFileData.size) +
totalStorageChanged;
return this.createDailyUsage(user.uuid, new Date(), delta);
}
const delta = totalStorageChanged;
console.log({ totalStorageChanged, delta });
return this.createDailyUsage(user.uuid, new Date(), delta);
} */

async addDailyUsageChangeOnFileSizeChange(
user: User,
oldFileData: File,
Expand Down
56 changes: 56 additions & 0 deletions test/fixtures.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from '../src/modules/workspaces/attributes/workspace-items-users.attributes';
import * as fixtures from './fixtures';
import { SharingActionName } from '../src/modules/sharing/sharing.domain';
import { newUsage } from './fixtures';
import { UsageType } from '../src/modules/usage/usage.domain';

describe('Testing fixtures tests', () => {
describe("User's fixture", () => {
Expand Down Expand Up @@ -582,4 +584,58 @@ describe('Testing fixtures tests', () => {
expect(role.name).toBe(customName);
});
});

describe('Usage Fixture', () => {
it('When it generates a usage, then it should be random', () => {
const usage = newUsage();
const otherUsage = newUsage();

expect(usage.id).toBeTruthy();
expect(usage.id).not.toBe(otherUsage.id);
expect(usage.userId).not.toBe(otherUsage.userId);
});

it('When it generates a usage, then the delta should be within the range', () => {
const usage = newUsage();

expect(usage.delta).toBeGreaterThanOrEqual(0);
expect(usage.delta).toBeLessThanOrEqual(1000);
});

it('When it generates a usage and a type is provided, then that type should be set', () => {
const usage = newUsage({ attributes: { type: UsageType.Monthly } });

expect(usage.type).toBe(UsageType.Monthly);
});

it('When it generates a usage, then the period should be populated', () => {
const usage = newUsage();

expect(usage.period).toBeInstanceOf(Date);
expect(usage.period).toBeTruthy();
});

it('When it generates a usage and custom attributes are provided, then those attributes should be set correctly', () => {
const customAttributes = {
delta: 500,
type: UsageType.Yearly,
period: new Date('2023-01-01T00:00:00Z'),
};

const usage = newUsage({ attributes: customAttributes });

expect(usage.delta).toBe(customAttributes.delta);
expect(usage.type).toBe(customAttributes.type);
expect(usage.period).toEqual(customAttributes.period);
});

it('When it generates multiple usages, then all their identifiers should be unique', () => {
const usages = Array.from({ length: 10 }, () => newUsage());

const ids = usages.map((usage) => usage.id);
const uniqueIds = new Set(ids);

expect(uniqueIds.size).toBe(usages.length);
});
});
});
Loading

0 comments on commit b3100c6

Please sign in to comment.