Skip to content

Commit 359de18

Browse files
authored
Merge pull request #133 from RafalMagrys/FIL-1087-reproduce-phantom-commit-and-fix-it
[Fil 1087] reproduce phantom commit and fix it
2 parents 90c8d79 + 4fa4320 commit 359de18

24 files changed

+1264
-128
lines changed

packages/application/src/application/events/handlers/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ export class AllocatorMultisigUpdatedEventHandler
124124
let threshold = 0;
125125
try {
126126
const msigData = await getMultisigInfo(event.multisigAddress);
127-
signers = msigData.multisig?.signers ?? [];
128-
threshold = msigData.multisig?.approvalThreshold ?? 0;
127+
signers = (msigData.multisig as { signers: string[] })?.signers ?? [];
128+
threshold = (msigData.multisig as { approvalThreshold: number })?.approvalThreshold ?? 0;
129129
} catch (err) {
130130
console.error(`Failed to fetch multisig info for ${event.multisigAddress}:`, err);
131131
}

packages/application/src/application/services/pull-request.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ export async function mapApplicationToPullRequestFile(
8585
const msigData = await getMultisigInfo(application.allocatorMultisigAddress);
8686

8787
if (msigData.robust !== application.allocatorMultisigAddress) {
88-
allocatorAddress = msigData.robust;
88+
allocatorAddress = msigData.robust ?? '';
8989
}
9090
allocatorId = msigData.address;
91-
const fetchedSigners = msigData.multisig.signers;
91+
const fetchedSigners = (msigData.multisig as { signers: string[] })?.signers ?? [];
9292
if (JSON.stringify(fetchedSigners) !== JSON.stringify(application.allocatorMultisigSigners)) {
9393
updatedSigners = fetchedSigners;
9494
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
import { DatacapAllocator } from '@src/domain/application/application';
4+
5+
import {
6+
CreateApplicationCommand,
7+
CreateApplicationCommandHandler,
8+
} from './create-application.command';
9+
import { Container } from 'inversify';
10+
import { TYPES } from '@src/types';
11+
12+
const baseCommandInput = {
13+
guid: 'guid-123',
14+
applicationId: 'app-123',
15+
applicationNumber: 42,
16+
applicantName: 'Test Applicant',
17+
applicantAddress: 'f01234',
18+
applicantOrgName: 'Test Org',
19+
applicantOrgAddresses: 'addr-1, addr-2',
20+
allocationTrancheSchedule: 'monthly',
21+
allocationAudit: 'audit',
22+
allocationDistributionRequired: 'distribution',
23+
allocationRequiredStorageProviders: 'providers',
24+
bookkeepingRepo: 'repo',
25+
allocationRequiredReplicas: 'replicas',
26+
datacapAllocationLimits: 'limits',
27+
applicantGithubHandle: 'main-handle',
28+
otherGithubHandles: '@FooUser, BarUser\n@baz-user',
29+
onChainAddressForDataCapAllocation: 'f09999',
30+
};
31+
32+
const mocks = vi.hoisted(() => ({
33+
getMultisigInfo: vi.fn(),
34+
logger: {
35+
info: vi.fn(),
36+
debug: vi.fn(),
37+
error: vi.fn(),
38+
warn: vi.fn(),
39+
},
40+
repository: {
41+
getById: vi.fn(),
42+
save: vi.fn(),
43+
},
44+
lotusClient: {
45+
getActorId: vi.fn(),
46+
},
47+
pullRequestService: {
48+
createPullRequest: vi.fn(),
49+
},
50+
}));
51+
52+
vi.mock('@src/infrastructure/clients/filfox', () => ({
53+
getMultisigInfo: mocks.getMultisigInfo,
54+
}));
55+
56+
describe('CreateApplicationCommandHandler', () => {
57+
let container: Container;
58+
let handler: CreateApplicationCommandHandler;
59+
60+
beforeEach(() => {
61+
vi.clearAllMocks();
62+
63+
container = new Container();
64+
container.bind(TYPES.Logger).toConstantValue(mocks.logger);
65+
container.bind(TYPES.DatacapAllocatorRepository).toConstantValue(mocks.repository);
66+
container.bind(TYPES.LotusClient).toConstantValue(mocks.lotusClient);
67+
container.bind(TYPES.PullRequestService).toConstantValue(mocks.pullRequestService);
68+
container.bind(CreateApplicationCommandHandler).toSelf();
69+
handler = container.get(CreateApplicationCommandHandler);
70+
71+
mocks.getMultisigInfo.mockResolvedValue({
72+
multisig: {
73+
signers: ['signer-1', 'signer-2'],
74+
approvalThreshold: 2,
75+
},
76+
});
77+
78+
mocks.pullRequestService.createPullRequest.mockResolvedValue({
79+
number: 1,
80+
url: 'https://github.com/test/test/pull/1',
81+
commentId: 1,
82+
});
83+
84+
mocks.lotusClient.getActorId.mockResolvedValue('f01234');
85+
});
86+
87+
describe('normalizeGithubHandles', () => {
88+
it('returns normalized handles', () => {
89+
const result = handler.normalizeGithubHandles('@Foo, Bar \n @baz');
90+
expect(result).toEqual(['foo', 'bar', 'baz']);
91+
});
92+
93+
it('returns an empty array when input is invalid', () => {
94+
const result = handler.normalizeGithubHandles('');
95+
expect(result).toEqual([]);
96+
});
97+
});
98+
99+
describe('handle', () => {
100+
it('returns an error when the application already exists', async () => {
101+
const existingAllocator = DatacapAllocator.create({
102+
applicationId: 'existing',
103+
applicationNumber: 1,
104+
applicantName: 'Existing',
105+
applicantAddress: 'f0',
106+
applicantOrgName: 'Org',
107+
applicantOrgAddresses: 'Addr',
108+
allocationTrancheSchedule: 'schedule',
109+
allocationAudit: 'audit',
110+
allocationDistributionRequired: 'dist',
111+
allocationRequiredStorageProviders: 'providers',
112+
bookkeepingRepo: 'repo',
113+
allocationRequiredReplicas: 'replicas',
114+
datacapAllocationLimits: 'limits',
115+
applicantGithubHandle: 'handle',
116+
otherGithubHandles: [],
117+
onChainAddressForDataCapAllocation: 'f011',
118+
});
119+
mocks.repository.getById.mockResolvedValue(existingAllocator);
120+
const result = await handler.handle(new CreateApplicationCommand(baseCommandInput));
121+
122+
expect(result).toStrictEqual({
123+
success: false,
124+
error: new Error('Application already exists'),
125+
});
126+
127+
expect(mocks.repository.save).not.toHaveBeenCalled();
128+
expect(mocks.pullRequestService.createPullRequest).not.toHaveBeenCalled();
129+
});
130+
131+
it('should save the application', async () => {
132+
mocks.repository.getById.mockRejectedValue(null);
133+
const createApplicationCommand = new CreateApplicationCommand(baseCommandInput);
134+
const result = await handler.handle(createApplicationCommand);
135+
136+
expect(result).toStrictEqual({
137+
success: true,
138+
data: { guid: baseCommandInput.guid },
139+
});
140+
141+
expect(mocks.pullRequestService.createPullRequest).toHaveBeenCalledWith(
142+
expect.any(DatacapAllocator),
143+
);
144+
expect(mocks.pullRequestService.createPullRequest).toHaveBeenCalledWith(
145+
expect.objectContaining({
146+
guid: baseCommandInput.applicationId,
147+
applicationNumber: baseCommandInput.applicationNumber,
148+
applicantName: baseCommandInput.applicantName,
149+
}),
150+
);
151+
152+
expect(mocks.repository.save).toHaveBeenCalledWith(expect.any(DatacapAllocator), -1);
153+
expect(mocks.repository.save).toHaveBeenCalledWith(
154+
expect.objectContaining({
155+
guid: baseCommandInput.applicationId,
156+
applicationNumber: baseCommandInput.applicationNumber,
157+
applicantName: baseCommandInput.applicantName,
158+
applicantAddress: baseCommandInput.applicantAddress,
159+
applicantOrgName: baseCommandInput.applicantOrgName,
160+
applicantOrgAddresses: baseCommandInput.applicantOrgAddresses,
161+
allocationTrancheSchedule: baseCommandInput.allocationTrancheSchedule,
162+
allocationAudit: baseCommandInput.allocationAudit,
163+
allocationDistributionRequired: baseCommandInput.allocationDistributionRequired,
164+
allocationRequiredStorageProviders: baseCommandInput.allocationRequiredStorageProviders,
165+
allocationBookkeepingRepo: baseCommandInput.bookkeepingRepo,
166+
allocationRequiredReplicas: baseCommandInput.allocationRequiredReplicas,
167+
allocationDatacapAllocationLimits: baseCommandInput.datacapAllocationLimits,
168+
applicantGithubHandle: baseCommandInput.applicantGithubHandle,
169+
onChainAddressForDataCapAllocation: baseCommandInput.onChainAddressForDataCapAllocation,
170+
allocatorActorId: 'f01234',
171+
allocatorMultisigAddress: baseCommandInput.onChainAddressForDataCapAllocation,
172+
allocatorMultisigSigners: ['signer-1', 'signer-2'],
173+
allocatorMultisigThreshold: 2,
174+
applicationPullRequest: expect.objectContaining({
175+
prNumber: 1,
176+
prUrl: 'https://github.com/test/test/pull/1',
177+
commentId: 1,
178+
}),
179+
}),
180+
-1,
181+
);
182+
});
183+
});
184+
});

0 commit comments

Comments
 (0)