Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ vi.mock('nanoid', () => ({
describe('ApproveRefreshByMaCommand', () => {
let container: Container;
let handler: ApproveRefreshByMaCommandHandler;
const fixtureDatacapAmount = 1;

const loggerMock = { info: vi.fn(), error: vi.fn() };
const commandBusMock = { send: vi.fn() };
const refreshAuditServiceMock = { finishAudit: vi.fn() };
const dataCapMapperMock = { fromBigIntBytesToPiBNumber: vi.fn().mockReturnValue(1) };
const dataCapMapperMock = {
fromBigIntBytesToPiBNumber: vi.fn().mockReturnValue(fixtureDatacapAmount),
};
const rpcProviderMock = {
getDcAllocatedDate: vi.fn(),
getBlock: vi.fn(),
Expand All @@ -39,13 +43,14 @@ describe('ApproveRefreshByMaCommand', () => {
ended: '2024-01-01T00:00:00.000Z',
dcAllocated: '2024-01-01T00:00:00.000Z',
outcome: 'MATCH',
datacapAmount: fixtureDatacapAmount,
},
branchName: 'b',
commitSha: 'c',
prNumber: 1,
prUrl: 'u',
};
const fixtureIssueDetails = DatabaseRefreshFactory.create();
const fixtureIssueDetails = DatabaseRefreshFactory.create({ dataCap: 0 });
const fixtureApproval: Approval = {
blockNumber: faker.number.int({ min: 1000, max: 9999 }),
txHash: faker.string.alphanumeric(66),
Expand Down Expand Up @@ -109,6 +114,7 @@ describe('ApproveRefreshByMaCommand', () => {
metaAllocator: {
blockNumber: fixtureApproval.blockNumber,
},
dataCap: fixtureDatacapAmount,
},
});
expect(loggerMock.info).toHaveBeenCalledTimes(2);
Expand Down Expand Up @@ -142,6 +148,7 @@ describe('ApproveRefreshByMaCommand', () => {
metaAllocator: {
blockNumber: fixtureApproval.blockNumber,
},
dataCap: fixtureDatacapAmount,
},
});
expect(commandBusMock.send).toHaveBeenCalledWith(expect.any(SaveIssueCommand));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { SaveIssueCommand } from '../refresh-issues/save-issue.command';
import { IRpcProvider } from '@src/infrastructure/clients/rpc-provider';

const LOG = LOG_MESSAGES.APPROVE_REFRESH_BY_MA_COMMAND;

export class ApproveRefreshByMaCommand extends Command {
constructor(
public readonly issueDetails: IssueDetails,
Expand Down Expand Up @@ -99,6 +98,7 @@ export class ApproveRefreshByMaCommandHandler
blockNumber: approval.blockNumber,
},
auditHistory,
dataCap: Number(auditResult.auditChange.datacapAmount) || 0,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import 'reflect-metadata';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Container } from 'inversify';
import { Logger } from '@filecoin-plus/core';
import {
convertToActorId,
handleMetaAllocatorIssueApproval,
handleMetaAllocatorApplicationApproval,
} from './subscribe-ma-approvals.service';
import { ApproveRefreshByMaCommand } from './approve-refresh-by-ma.command';
import { UpdateMetaAllocatorApprovalsCommand } from './update-ma-approvals.command';
import { IIssueDetailsRepository } from '@src/infrastructure/repositories/issue-details.repository';
import { IApplicationDetailsRepository } from '@src/infrastructure/repositories/application-details.repository';
import { IRpcProvider } from '@src/infrastructure/clients/rpc-provider';
import { TYPES } from '@src/types';

const baseApproval = {
blockNumber: 1234,
txHash: '0xabc',
contractAddress: '0xcontract',
allocatorAddress: '0xallocator',
allowanceBefore: '1',
allowanceAfter: '2',
};

const defaultActorId = 'f01234';

vi.mock('@src/config', () => ({
default: {
MONGODB_URI: 'mongodb://localhost:27017',
DB_NAME: 'test-db',
},
}));

describe('subscribe-meta-allocator-approvals helpers', () => {
let container: Container;
let logger: Logger;
let rpcProvider: IRpcProvider;
let issuesRepository: IIssueDetailsRepository;
let applicationDetailsRepository: IApplicationDetailsRepository;

const loggerMock = {
info: vi.fn((...args) => console.log(...args)),
error: vi.fn((...args) => console.error(...args)),
debug: vi.fn((...args) => console.debug(...args)),
};
const rpcProviderMock = {
send: vi.fn(),
};
const issuesRepositoryMock = {
findPendingBy: vi.fn(),
};
const applicationDetailsRepositoryMock = {
getPendingBy: vi.fn(),
};

beforeEach(() => {
container = new Container();

container.bind<Logger>(TYPES.Logger).toConstantValue(loggerMock as unknown as Logger);
container
.bind<IRpcProvider>(TYPES.RpcProvider)
.toConstantValue(rpcProviderMock as unknown as IRpcProvider);
container
.bind<IIssueDetailsRepository>(TYPES.IssueDetailsRepository)
.toConstantValue(issuesRepositoryMock as unknown as IIssueDetailsRepository);
container
.bind<IApplicationDetailsRepository>(TYPES.ApplicationDetailsRepository)
.toConstantValue(
applicationDetailsRepositoryMock as unknown as IApplicationDetailsRepository,
);

logger = container.get<Logger>(TYPES.Logger);
rpcProvider = container.get<IRpcProvider>(TYPES.RpcProvider) as unknown as typeof rpcProvider;
issuesRepository = container.get<IIssueDetailsRepository>(
TYPES.IssueDetailsRepository,
) as unknown as typeof issuesRepository;
applicationDetailsRepository = container.get<IApplicationDetailsRepository>(
TYPES.ApplicationDetailsRepository,
) as unknown as typeof applicationDetailsRepository;

issuesRepositoryMock.findPendingBy.mockResolvedValue({
id: 'issue-1',
actorId: defaultActorId,
});
applicationDetailsRepositoryMock.getPendingBy.mockResolvedValue({
id: 'app-1',
actorId: defaultActorId,
});
});

describe('convertToActorId', () => {
it('returns the same allocatorAddress when it is already a Filecoin address', async () => {
const allocatorAddress = 'f01234';

const result = await convertToActorId({
allocatorAddress,
logger,
rpcProvider: rpcProvider as unknown as IRpcProvider,
});

expect(result).toBe(allocatorAddress);
expect(rpcProvider.send).not.toHaveBeenCalled();
});

it('converts an Ethereum address to a Filecoin actor id using rpc provider', async () => {
const allocatorAddress = '0x1234';
const expectedFilecoinId = 'f05678';
rpcProviderMock.send.mockResolvedValue(expectedFilecoinId);

const result = await convertToActorId({
allocatorAddress,
logger,
rpcProvider: rpcProvider as unknown as IRpcProvider,
});

expect(rpcProvider.send).toHaveBeenCalledWith('Filecoin.EthAddressToFilecoinAddress', [
allocatorAddress,
]);
expect(result).toBe(expectedFilecoinId);
});
});

describe('handleMetaAllocatorIssueApproval', () => {
it('creates ApproveRefreshByMaCommand when issue exists', async () => {
const command = await handleMetaAllocatorIssueApproval({
approval: baseApproval as any,
actorId: defaultActorId,
issuesRepository: issuesRepository as unknown as IIssueDetailsRepository,
});

expect(issuesRepository.findPendingBy).toHaveBeenCalledWith({ actorId: defaultActorId });
expect(command).toBeInstanceOf(ApproveRefreshByMaCommand);
});

it('throws when issue is not found', async () => {
const actorId = 'f09999';
issuesRepositoryMock.findPendingBy.mockResolvedValue(null);

await expect(
handleMetaAllocatorIssueApproval({
approval: baseApproval as any,
actorId,
issuesRepository: issuesRepository as unknown as IIssueDetailsRepository,
}),
).rejects.toThrowError(/Issue not found/);
});
});

describe('handleMetaAllocatorApplicationApproval', () => {
it('creates UpdateMetaAllocatorApprovalsCommand when application details exist', async () => {
const actorId = defaultActorId;

const command = await handleMetaAllocatorApplicationApproval({
approval: baseApproval as any,
actorId,
applicationDetailsRepository:
applicationDetailsRepository as unknown as IApplicationDetailsRepository,
});

expect(applicationDetailsRepository.getPendingBy).toHaveBeenCalledWith('actorId', actorId);
expect(command).toBeInstanceOf(UpdateMetaAllocatorApprovalsCommand);
});

it('throws when application details are not found', async () => {
const actorId = 'f09999';
applicationDetailsRepositoryMock.getPendingBy.mockResolvedValue(null);

await expect(
handleMetaAllocatorApplicationApproval({
approval: baseApproval as any,
actorId,
applicationDetailsRepository:
applicationDetailsRepository as unknown as IApplicationDetailsRepository,
}),
).rejects.toThrowError(/Application details not found/);
});
});
});