Skip to content

Commit a10d31f

Browse files
Le-CaignecgfournierProzguesmi
authored
feat: add unit tests for Bulk and BulkSlice entities (#59)
Co-authored-by: gfournieriExec <[email protected]> Co-authored-by: gfournieriExec <[email protected]> Co-authored-by: Zied Guesmi <[email protected]>
1 parent 0462170 commit a10d31f

File tree

3 files changed

+527
-2
lines changed

3 files changed

+527
-2
lines changed

tests/unit/Modules/Bulk.test.ts

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// SPDX-FileCopyrightText: 2025 IEXEC BLOCKCHAIN TECH <[email protected]>
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { BigInt, Bytes, DataSourceContext } from '@graphprotocol/graph-ts';
5+
import {
6+
assert,
7+
beforeEach,
8+
clearStore,
9+
dataSourceMock,
10+
describe,
11+
test,
12+
} from 'matchstick-as/assembly/index';
13+
import { BulkSlice, DatasetOrder } from '../../../generated/schema';
14+
import { handleBulk, handleBulkSlice } from '../../../src/Modules/Bulk';
15+
import {
16+
CONTEXT_BOT_FIRST,
17+
CONTEXT_BOT_SIZE,
18+
CONTEXT_BULK,
19+
CONTEXT_DEAL,
20+
CONTEXT_INDEX,
21+
createBulkOrderID,
22+
createBulkSliceID,
23+
} from '../../../src/utils';
24+
import { mockAddress, mockBytes32 } from '../utils/mock';
25+
26+
const dealId = mockBytes32('dealId');
27+
28+
describe('Bulk Module', () => {
29+
beforeEach(() => {
30+
clearStore();
31+
});
32+
33+
describe('handleBulk', () => {
34+
test('Should create Bulk entity from JSON content', () => {
35+
// --- GIVEN
36+
const bulkId = dealId.toHex();
37+
const hash = 'QmBulkHash';
38+
const botFirst = BigInt.fromI32(0);
39+
const botSize = BigInt.fromI32(2);
40+
41+
// Create JSON content with slice CIDs
42+
const jsonContent = '["QmSlice1", "QmSlice2", "QmSlice3"]';
43+
const content = Bytes.fromUTF8(jsonContent);
44+
45+
// Mock dataSource
46+
let context = new DataSourceContext();
47+
context.setString(CONTEXT_DEAL, bulkId);
48+
context.setBigInt(CONTEXT_BOT_FIRST, botFirst);
49+
context.setBigInt(CONTEXT_BOT_SIZE, botSize);
50+
51+
dataSourceMock.setReturnValues(hash, 'network', context);
52+
53+
// --- WHEN
54+
handleBulk(content);
55+
56+
// --- THEN
57+
assert.fieldEquals('Bulk', bulkId, 'id', bulkId);
58+
assert.fieldEquals('Bulk', bulkId, 'hash', hash);
59+
});
60+
});
61+
62+
describe('handleBulkSlice', () => {
63+
test('Should create BulkSlice entity from JSON content with empty dataset order', () => {
64+
// --- GIVEN
65+
const bulkId = dealId.toHex();
66+
const index = BigInt.fromI32(0);
67+
const hash = 'QmSliceHash';
68+
const sliceId = createBulkSliceID(bulkId, index);
69+
70+
// Create JSON content with empty dataset orders array
71+
const jsonContent = '[]';
72+
const content = Bytes.fromUTF8(jsonContent);
73+
74+
let context = new DataSourceContext();
75+
context.setString(CONTEXT_BULK, bulkId);
76+
context.setString(CONTEXT_DEAL, bulkId);
77+
context.setBigInt(CONTEXT_INDEX, index);
78+
79+
dataSourceMock.setReturnValues(hash, 'network', context);
80+
81+
// --- WHEN
82+
handleBulkSlice(content);
83+
84+
// --- THEN
85+
assert.fieldEquals('BulkSlice', sliceId, 'id', sliceId);
86+
assert.fieldEquals('BulkSlice', sliceId, 'hash', hash);
87+
assert.fieldEquals('BulkSlice', sliceId, 'bulk', bulkId);
88+
assert.fieldEquals('BulkSlice', sliceId, 'index', index.toString());
89+
90+
// Verify no dataset orders are created
91+
let loadedSlice = BulkSlice.load(sliceId);
92+
assert.assertTrue(loadedSlice != null);
93+
assert.i32Equals(loadedSlice!.datasetOrders.length, 0);
94+
assert.i32Equals(loadedSlice!.datasets.length, 0);
95+
});
96+
97+
test('Should create BulkSlice entity from JSON content with a dataset order', () => {
98+
// --- GIVEN
99+
const bulkId = dealId.toHex();
100+
const index = BigInt.fromI32(0);
101+
const hash = 'QmSliceHash';
102+
const sliceId = createBulkSliceID(bulkId, index);
103+
const datasetAddr = mockAddress('dataset').toHex().toLowerCase();
104+
const datasetPrice = '1000000000';
105+
const volume = '1';
106+
const appAddr = mockAddress('app').toHex().toLowerCase();
107+
const poolAddr = mockAddress('pool').toHex().toLowerCase();
108+
const requesterAddr = mockAddress('requester').toHex().toLowerCase();
109+
const tagHex = mockBytes32('tag').toHex();
110+
const saltHex = mockBytes32('salt').toHex();
111+
const signHex = '0x1234';
112+
113+
// Create JSON content with one valid dataset order
114+
const jsonContent = `[{
115+
"dataset": "${datasetAddr}",
116+
"datasetprice": "${datasetPrice}",
117+
"volume": "${volume}",
118+
"tag": "${tagHex}",
119+
"apprestrict": "${appAddr}",
120+
"workerpoolrestrict": "${poolAddr}",
121+
"requesterrestrict": "${requesterAddr}",
122+
"salt": "${saltHex}",
123+
"sign": "${signHex}"
124+
}]`;
125+
const content = Bytes.fromUTF8(jsonContent);
126+
127+
let context = new DataSourceContext();
128+
context.setString(CONTEXT_BULK, bulkId);
129+
context.setString(CONTEXT_DEAL, bulkId);
130+
context.setBigInt(CONTEXT_INDEX, index);
131+
132+
dataSourceMock.setReturnValues(hash, 'network', context);
133+
134+
// --- WHEN
135+
handleBulkSlice(content);
136+
137+
// --- THEN
138+
assert.fieldEquals('BulkSlice', sliceId, 'id', sliceId);
139+
140+
// Verify BulkSlice has dataset order
141+
let loadedSlice = BulkSlice.load(sliceId);
142+
assert.assertTrue(loadedSlice != null);
143+
assert.i32Equals(loadedSlice!.datasetOrders.length, 1);
144+
assert.i32Equals(loadedSlice!.datasets.length, 1);
145+
assert.stringEquals(loadedSlice!.datasets[0], datasetAddr);
146+
});
147+
});
148+
149+
describe('DatasetOrder in BulkSlice context', () => {
150+
test('Should link multiple DatasetOrders to a BulkSlice', () => {
151+
// --- GIVEN
152+
const bulkId = dealId.toHex();
153+
const index = BigInt.fromI32(0);
154+
const sliceId = createBulkSliceID(dealId.toHex(), index);
155+
const taskId = mockBytes32('task').toHex();
156+
157+
// Create dataset orders
158+
const orderIds: string[] = [];
159+
const datasetAddresses: string[] = [];
160+
161+
for (let i = 0; i < 2; i++) {
162+
const orderIndex = BigInt.fromI32(i);
163+
const datasetOrderId = createBulkOrderID(taskId, orderIndex);
164+
const datasetAddress = mockAddress('dataset' + i.toString()).toHex();
165+
166+
let datasetOrder = new DatasetOrder(datasetOrderId);
167+
datasetOrder.dataset = datasetAddress;
168+
datasetOrder.datasetprice = BigInt.fromI32(i + 1).toBigDecimal();
169+
datasetOrder.volume = BigInt.fromI32(1);
170+
datasetOrder.tag = mockBytes32('tag');
171+
datasetOrder.apprestrict = mockAddress('app');
172+
datasetOrder.workerpoolrestrict = mockAddress('pool');
173+
datasetOrder.requesterrestrict = mockAddress('requester');
174+
datasetOrder.salt = mockBytes32('salt');
175+
datasetOrder.sign = mockBytes32('sign');
176+
datasetOrder.save();
177+
178+
orderIds.push(datasetOrderId);
179+
datasetAddresses.push(datasetAddress);
180+
}
181+
182+
// --- WHEN
183+
// Create BulkSlice with dataset orders
184+
let bulkSlice = new BulkSlice(sliceId);
185+
bulkSlice.task = taskId;
186+
bulkSlice.hash = 'QmSlice';
187+
bulkSlice.bulk = bulkId;
188+
bulkSlice.index = index;
189+
bulkSlice.datasets = datasetAddresses;
190+
bulkSlice.datasetOrders = orderIds;
191+
bulkSlice.save();
192+
193+
// --- THEN
194+
// Verify
195+
let loadedSlice = BulkSlice.load(sliceId);
196+
assert.assertTrue(loadedSlice != null);
197+
assert.i32Equals(loadedSlice!.datasetOrders.length, 2);
198+
assert.stringEquals(loadedSlice!.datasetOrders[0], orderIds[0]);
199+
assert.stringEquals(loadedSlice!.datasetOrders[1], orderIds[1]);
200+
});
201+
});
202+
});

tests/unit/Modules/IexecPoco.test.ts

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
// SPDX-FileCopyrightText: 2024-2025 IEXEC BLOCKCHAIN TECH <[email protected]>
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { BigInt, ethereum } from '@graphprotocol/graph-ts';
5-
import { assert, describe, newTypedMockEventWithParams, test } from 'matchstick-as/assembly/index';
4+
import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts';
5+
import {
6+
assert,
7+
beforeEach,
8+
clearStore,
9+
describe,
10+
newTypedMockEventWithParams,
11+
test,
12+
} from 'matchstick-as/assembly/index';
613
import { OrdersMatched } from '../../../generated/Core/IexecInterfaceToken';
714
import { handleOrdersMatched } from '../../../src/Modules';
815
import { toRLC } from '../../../src/utils';
@@ -40,6 +47,10 @@ const schedulerRewardRatio = BigInt.fromI32(10);
4047
const sponsor = mockAddress('sponsor');
4148

4249
describe('IexecPoco', () => {
50+
beforeEach(() => {
51+
clearStore();
52+
});
53+
4354
test('Should handle OrdersMatched', () => {
4455
mockViewDeal(pocoAddress, dealId).returns([buildDefaultDeal()]);
4556
// Create the mock event
@@ -105,6 +116,65 @@ describe('IexecPoco', () => {
105116
const transactionId = mockEvent.transaction.hash.toHex();
106117
assert.fieldEquals('Transaction', transactionId, 'id', transactionId);
107118
});
119+
120+
test('Should handle OrdersMatched with bulk_cid when no dataset', () => {
121+
const bulkCid = 'QmBulkCID123456789';
122+
const paramsWithBulkCid = `{"bulk_cid": "${bulkCid}"}`;
123+
124+
// Create a deal without dataset (Address.zero()) but with bulk_cid in params
125+
const dealWithBulkCid = buildDeal(
126+
appAddress,
127+
appOwner,
128+
appPrice,
129+
Address.zero(), // zero address for dataset
130+
Address.zero(), // zero address for dataset owner
131+
BigInt.zero(), // zero price for dataset
132+
workerpoolAddress,
133+
workerpoolOwner,
134+
workerpoolPrice,
135+
trust,
136+
category,
137+
tag,
138+
requester,
139+
beneficiary,
140+
callback,
141+
paramsWithBulkCid, // params containing bulk_cid
142+
startTime,
143+
botFirst,
144+
botSize,
145+
workerStake,
146+
schedulerRewardRatio,
147+
sponsor,
148+
);
149+
150+
mockViewDeal(pocoAddress, dealId).returns([dealWithBulkCid]);
151+
152+
// Create the mock event
153+
let mockEvent = newTypedMockEventWithParams<OrdersMatched>(
154+
EventParamBuilder.init()
155+
.bytes('dealid', dealId)
156+
.bytes('appHash', appHash)
157+
.bytes('datasetHash', datasetHash)
158+
.bytes('workerpoolHash', workerpoolHash)
159+
.bytes('requestHash', requestHash)
160+
.build(),
161+
);
162+
mockEvent.block.timestamp = timestamp;
163+
mockEvent.address = pocoAddress;
164+
165+
// Call the handler
166+
handleOrdersMatched(mockEvent);
167+
168+
// Assert that the deal was created with bulk reference
169+
assert.fieldEquals(
170+
'Deal',
171+
dealId.toHex(),
172+
'dataset',
173+
'0x0000000000000000000000000000000000000000',
174+
);
175+
assert.fieldEquals('Deal', dealId.toHex(), 'bulk', dealId.toHex()); // bulk ID should be the dealId
176+
assert.fieldEquals('Deal', dealId.toHex(), 'params', paramsWithBulkCid);
177+
});
108178
});
109179

110180
function buildDefaultDeal(): ethereum.Value {

0 commit comments

Comments
 (0)