Skip to content

Commit ba5e4bf

Browse files
authored
Merge pull request #127 from RafalMagrys/FIL-1067-rkhp-allow-meta-allocator-to-allocate-dc-without-gov-approval
[Fil 1067] rkhp allow meta allocator to allocate dc without gov approval
2 parents 94d7621 + 3fd12f3 commit ba5e4bf

17 files changed

+429
-113
lines changed

packages/application/src/application/resolvers/audit-outcome-resolver.test.ts

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,26 @@ describe('AuditOutcomeResolver', () => {
88
let container: Container;
99
let service: AuditOutcomeResolver;
1010

11-
const createAuditCycle = (dc: number) => ({
12-
started: '',
13-
ended: '',
14-
dc_allocated: '',
15-
outcome: '',
16-
datacap_amount: dc,
17-
});
18-
1911
beforeEach(() => {
2012
container = new Container();
2113
container.bind<AuditOutcomeResolver>(TYPES.AuditOutcomeResolver).to(AuditOutcomeResolver);
2214

2315
service = container.get<AuditOutcomeResolver>(TYPES.AuditOutcomeResolver);
2416
});
2517

26-
it('returns MATCH when datacap is unchanged compared to previous audit', () => {
27-
expect(service.resolve(createAuditCycle(10), createAuditCycle(10))).toBe(AuditOutcome.MATCH);
28-
});
29-
30-
it('returns DOUBLE when current equals previous * 2', () => {
31-
expect(service.resolve(createAuditCycle(10), createAuditCycle(20))).toBe(AuditOutcome.DOUBLE);
32-
});
33-
34-
it('returns THROTTLE when current equals previous / 2', () => {
35-
expect(service.resolve(createAuditCycle(10), createAuditCycle(5))).toBe(AuditOutcome.THROTTLE);
36-
});
37-
38-
it('returns UNKNOWN for all other cases', () => {
39-
expect(service.resolve(createAuditCycle(0), createAuditCycle(7))).toBe(AuditOutcome.UNKNOWN);
40-
expect(service.resolve(createAuditCycle(10), createAuditCycle(0))).toBe(AuditOutcome.UNKNOWN);
41-
expect(service.resolve(createAuditCycle(7), createAuditCycle(8))).toBe(AuditOutcome.UNKNOWN);
42-
expect(service.resolve(createAuditCycle(8), createAuditCycle(7))).toBe(AuditOutcome.UNKNOWN);
43-
});
18+
it.each`
19+
prevDatacap | currentDatacap | expected
20+
${10} | ${10} | ${AuditOutcome.MATCH}
21+
${10} | ${20} | ${AuditOutcome.DOUBLE}
22+
${10} | ${5} | ${AuditOutcome.THROTTLE}
23+
${0} | ${7} | ${AuditOutcome.UNKNOWN}
24+
${10} | ${0} | ${AuditOutcome.UNKNOWN}
25+
${7} | ${8} | ${AuditOutcome.UNKNOWN}
26+
${8} | ${7} | ${AuditOutcome.UNKNOWN}
27+
`(
28+
'returns $expected when prevDatacap is $prevDatacap and currentDatacap is $currentDatacap',
29+
({ prevDatacap, currentDatacap, expected }) => {
30+
expect(service.resolve(prevDatacap, currentDatacap)).toBe(expected);
31+
},
32+
);
4433
});

packages/application/src/application/resolvers/audit-outcome-resolver.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import { injectable } from 'inversify';
22
import { AuditOutcome } from '@src/infrastructure/repositories/issue-details';
3-
import { AuditCycle } from '../services/pull-request.types';
43

54
@injectable()
65
export class AuditOutcomeResolver {
7-
resolve(prevAudit?: AuditCycle, currentAudit?: AuditCycle): AuditOutcome {
8-
if (!prevAudit || !currentAudit) return AuditOutcome.UNKNOWN;
9-
10-
const prevDatacap = prevAudit.datacap_amount;
11-
const currentDatacap = currentAudit.datacap_amount;
6+
resolve(prevDatacap?: number | '', currentDatacap?: number | ''): AuditOutcome {
7+
if (!prevDatacap || !currentDatacap) return AuditOutcome.UNKNOWN;
128

139
switch (true) {
1410
case prevDatacap === currentDatacap:

packages/application/src/application/services/refresh-audit.service.test.ts

Lines changed: 181 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Container } from 'inversify';
44
import { TYPES } from '@src/types';
55
import { AuditOutcome } from '@src/infrastructure/repositories/issue-details';
66
import { RefreshAuditService } from './refresh-audit.service';
7+
import { AuditOutcomeResolver } from '../resolvers/audit-outcome-resolver';
78

89
describe('RefreshAuditService', () => {
910
let container: Container;
@@ -14,16 +15,12 @@ describe('RefreshAuditService', () => {
1415
updateAudit: vi.fn(),
1516
};
1617

17-
const auditOutcomeResolverMock = {
18-
resolve: vi.fn(),
19-
};
20-
2118
const jsonHash = 'rec123abc';
2219

2320
beforeEach(() => {
2421
container = new Container();
2522
container.bind(TYPES.RefreshAuditPublisher).toConstantValue(refreshAuditPublisherMock);
26-
container.bind(TYPES.AuditOutcomeResolver).toConstantValue(auditOutcomeResolverMock);
23+
container.bind(TYPES.AuditOutcomeResolver).to(AuditOutcomeResolver).inSingletonScope();
2724
container.bind<RefreshAuditService>(TYPES.RefreshAuditService).to(RefreshAuditService);
2825
service = container.get<RefreshAuditService>(TYPES.RefreshAuditService);
2926

@@ -32,67 +29,197 @@ describe('RefreshAuditService', () => {
3229
vi.clearAllMocks();
3330
});
3431

35-
it('startAudit calls publisher.newAudit and returns result', async () => {
36-
const expected = { auditChange: {}, branchName: 'b', commitSha: 'c', prNumber: 1, prUrl: 'u' };
37-
refreshAuditPublisherMock.newAudit.mockResolvedValue(expected);
32+
describe('startAudit', () => {
33+
it('startAudit calls publisher.newAudit and returns result', async () => {
34+
const expected = {
35+
auditChange: {},
36+
branchName: 'b',
37+
commitSha: 'c',
38+
prNumber: 1,
39+
prUrl: 'u',
40+
};
41+
refreshAuditPublisherMock.newAudit.mockResolvedValue(expected);
3842

39-
const result = await service.startAudit(jsonHash);
43+
const result = await service.startAudit(jsonHash);
4044

41-
expect(refreshAuditPublisherMock.newAudit).toHaveBeenCalledWith(jsonHash);
42-
expect(result).toBe(expected);
45+
expect(refreshAuditPublisherMock.newAudit).toHaveBeenCalledWith(jsonHash);
46+
expect(result).toBe(expected);
47+
});
4348
});
4449

45-
it('approveAudit sets ended and APPROVED outcome', async () => {
46-
const datacapAmount = 10;
47-
const expectedChange = {
48-
ended: new Date().toISOString(),
49-
outcome: AuditOutcome.APPROVED,
50-
};
51-
refreshAuditPublisherMock.updateAudit.mockResolvedValue({
52-
auditChange: expectedChange,
53-
branchName: 'b',
54-
commitSha: 'c',
55-
prNumber: 1,
56-
prUrl: 'u',
57-
});
50+
describe('approveAudit', () => {
51+
it('approveAudit sets ended and APPROVED outcome', async () => {
52+
const datacapAmount = 10;
53+
const expectedChange = {
54+
ended: new Date().toISOString(),
55+
outcome: AuditOutcome.APPROVED,
56+
};
57+
refreshAuditPublisherMock.updateAudit.mockResolvedValue({
58+
auditChange: expectedChange,
59+
branchName: 'b',
60+
commitSha: 'c',
61+
prNumber: 1,
62+
prUrl: 'u',
63+
});
5864

59-
const result = await service.approveAudit(jsonHash, datacapAmount);
65+
const result = await service.approveAudit(jsonHash, datacapAmount);
6066

61-
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
62-
jsonHash,
63-
{
64-
datacapAmount,
67+
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
68+
jsonHash,
69+
{
70+
datacapAmount,
71+
ended: new Date().toISOString(),
72+
outcome: AuditOutcome.APPROVED,
73+
},
74+
[AuditOutcome.PENDING],
75+
);
76+
expect(result.auditChange).toEqual(expectedChange);
77+
});
78+
});
79+
80+
describe('rejectAudit', () => {
81+
it('rejectAudit sets ended and REJECTED outcome', async () => {
82+
const expectedChange = {
6583
ended: new Date().toISOString(),
66-
outcome: AuditOutcome.APPROVED,
67-
},
68-
[AuditOutcome.PENDING],
69-
);
70-
expect(result.auditChange).toEqual(expectedChange);
84+
outcome: AuditOutcome.REJECTED,
85+
};
86+
refreshAuditPublisherMock.updateAudit.mockResolvedValue({
87+
auditChange: expectedChange,
88+
branchName: 'b',
89+
commitSha: 'c',
90+
prNumber: 1,
91+
prUrl: 'u',
92+
});
93+
94+
const result = await service.rejectAudit(jsonHash);
95+
96+
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
97+
jsonHash,
98+
{
99+
ended: new Date().toISOString(),
100+
outcome: AuditOutcome.REJECTED,
101+
},
102+
[AuditOutcome.PENDING],
103+
);
104+
expect(result.auditChange).toEqual(expectedChange);
105+
});
71106
});
72107

73-
it('rejectAudit sets ended and REJECTED outcome', async () => {
74-
const expectedChange = {
75-
ended: new Date().toISOString(),
76-
outcome: AuditOutcome.REJECTED,
108+
describe('finishAudit', () => {
109+
const fixtureNow = new Date('2024-01-01T00:00:00.000Z');
110+
const grantedAudit = {
111+
ended: '2023-01-01T00:00:00.000Z',
112+
outcome: AuditOutcome.GRANTED,
113+
datacap_amount: 10,
114+
dc_allocated: '2024-01-01T00:00:00.000Z',
115+
started: '2022-01-01T00:00:00.000Z',
116+
};
117+
const pendingAudit = {
118+
started: '2024-01-01T00:00:00.000Z',
119+
outcome: AuditOutcome.PENDING,
77120
};
78-
refreshAuditPublisherMock.updateAudit.mockResolvedValue({
79-
auditChange: expectedChange,
80-
branchName: 'b',
81-
commitSha: 'c',
82-
prNumber: 1,
83-
prUrl: 'u',
121+
const approvedAudit = {
122+
started: '2022-01-01T00:00:00.000Z',
123+
ended: '2023-01-01T00:00:00.000Z',
124+
outcome: AuditOutcome.APPROVED,
125+
datacap_amount: 20,
126+
};
127+
128+
beforeEach(() => {
129+
vi.useFakeTimers();
130+
vi.setSystemTime(fixtureNow);
84131
});
85132

86-
const result = await service.rejectAudit(jsonHash);
133+
it('finishAudit sets ended outcome and dcAllocated and newDatacapAmount', async () => {
134+
const fixtureAllocator = {
135+
audits: [grantedAudit, pendingAudit],
136+
};
137+
refreshAuditPublisherMock.updateAudit.mockImplementation((_, callback) => {
138+
return {
139+
auditChange: callback(fixtureAllocator),
140+
branchName: 'b',
141+
commitSha: 'c',
142+
prNumber: 1,
143+
prUrl: 'u',
144+
};
145+
});
87146

88-
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
89-
jsonHash,
90-
{
91-
ended: new Date().toISOString(),
92-
outcome: AuditOutcome.REJECTED,
93-
},
94-
[AuditOutcome.PENDING],
95-
);
96-
expect(result.auditChange).toEqual(expectedChange);
147+
const result = await service.finishAudit(jsonHash, {
148+
newDatacapAmount: 10,
149+
dcAllocatedDate: new Date().toISOString(),
150+
});
151+
152+
expect(result.auditChange).toEqual({
153+
ended: fixtureNow.toISOString(),
154+
dcAllocated: fixtureNow.toISOString(),
155+
datacapAmount: 10,
156+
outcome: AuditOutcome.MATCH,
157+
});
158+
159+
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
160+
jsonHash,
161+
expect.any(Function),
162+
[AuditOutcome.PENDING, AuditOutcome.APPROVED],
163+
);
164+
});
165+
166+
it('finishAudit sets dcAllocatedDate and outcome and does not change ended date and datacapAmount', async () => {
167+
const fixtureAllocator = {
168+
audits: [grantedAudit, approvedAudit],
169+
};
170+
refreshAuditPublisherMock.updateAudit.mockImplementation((_, callback) => {
171+
return {
172+
auditChange: callback(fixtureAllocator),
173+
branchName: 'b',
174+
commitSha: 'c',
175+
prNumber: 1,
176+
prUrl: 'u',
177+
};
178+
});
179+
180+
const result = await service.finishAudit(jsonHash, {
181+
dcAllocatedDate: fixtureNow.toISOString(),
182+
});
183+
184+
expect(result.auditChange).toEqual({
185+
ended: fixtureAllocator.audits[1].ended,
186+
datacapAmount: fixtureAllocator.audits[1].datacap_amount,
187+
dcAllocated: fixtureNow.toISOString(),
188+
outcome: AuditOutcome.DOUBLE,
189+
});
190+
191+
expect(refreshAuditPublisherMock.updateAudit).toHaveBeenCalledWith(
192+
jsonHash,
193+
expect.any(Function),
194+
[AuditOutcome.PENDING, AuditOutcome.APPROVED],
195+
);
196+
});
197+
198+
it('finishAudit sets ended and unknown outcome and datacapAmount', async () => {
199+
const fixtureAllocator = {
200+
audits: [grantedAudit, pendingAudit],
201+
};
202+
refreshAuditPublisherMock.updateAudit.mockImplementation((_, callback) => {
203+
return {
204+
auditChange: callback(fixtureAllocator),
205+
branchName: 'b',
206+
commitSha: 'c',
207+
prNumber: 1,
208+
prUrl: 'u',
209+
};
210+
});
211+
212+
const result = await service.finishAudit(jsonHash, {
213+
newDatacapAmount: 100,
214+
dcAllocatedDate: fixtureNow.toISOString(),
215+
});
216+
217+
expect(result.auditChange).toEqual({
218+
ended: fixtureNow.toISOString(),
219+
datacapAmount: 100,
220+
dcAllocated: fixtureNow.toISOString(),
221+
outcome: AuditOutcome.UNKNOWN,
222+
});
223+
});
97224
});
98225
});

0 commit comments

Comments
 (0)