Skip to content

Commit 2e702f4

Browse files
committed
feat: add remainingAccess tests for dataProtectorCore.getGrantedAccess function
1 parent 6739dc2 commit 2e702f4

File tree

1 file changed

+326
-1
lines changed

1 file changed

+326
-1
lines changed

packages/sdk/tests/e2e/dataProtectorCore/getGrantedAccess.test.ts

Lines changed: 326 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { describe, it, expect } from '@jest/globals';
1+
import { describe, it, expect, beforeAll, jest } from '@jest/globals';
22
import { HDNodeWallet, Wallet } from 'ethers';
3+
import { IExec } from 'iexec';
4+
import BN from 'bn.js';
35
import { IExecDataProtectorCore } from '../../../src/index.js';
46
import {
57
MAX_EXPECTED_BLOCKTIME,
@@ -244,6 +246,329 @@ describe('dataProtectorCore.getGrantedAccess()', () => {
244246
);
245247
});
246248

249+
describe('remainingAccess', () => {
250+
let iexec: IExec;
251+
let sconeAppAddress: string;
252+
let workerpoolAddress: string;
253+
254+
beforeAll(async () => {
255+
// Setup app and workerpool for processing
256+
const [ethProvider, options] = getTestConfig(wallet.privateKey);
257+
sconeAppAddress = await deployRandomApp({
258+
ethProvider,
259+
teeFramework: 'scone',
260+
});
261+
262+
iexec = new IExec({ ethProvider }, options.iexecOptions);
263+
264+
// Create and publish app order
265+
await iexec.order
266+
.createApporder({
267+
app: sconeAppAddress,
268+
volume: 1000,
269+
tag: ['tee', 'scone']
270+
})
271+
.then(iexec.order.signApporder)
272+
.then(iexec.order.publishApporder);
273+
274+
// Deploy workerpool
275+
const { address: workerpool } = await iexec.workerpool.deployWorkerpool({
276+
description: 'test pool for remainingAccess',
277+
owner: await iexec.wallet.getAddress(),
278+
});
279+
workerpoolAddress = workerpool;
280+
281+
// Create and publish workerpool order
282+
await iexec.order
283+
.createWorkerpoolorder({
284+
workerpool: workerpoolAddress,
285+
category: 0,
286+
volume: 1000,
287+
tag: ['tee', 'scone'],
288+
})
289+
.then(iexec.order.signWorkerpoolorder)
290+
.then(iexec.order.publishWorkerpoolorder);
291+
}, 6 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME);
292+
293+
describe('Basic decrementing', () => {
294+
it(
295+
'should show 5 remaining access before sending any email, then 4 after processing once',
296+
async () => {
297+
// Create a protected data
298+
const protectedData = await dataProtectorCore.protectData({
299+
data: { email: '[email protected]' },
300+
name: 'test protected data for decrementing',
301+
});
302+
303+
const userAddress = await iexec.wallet.getAddress();
304+
305+
// Grant access to yourself with volume = 5
306+
const accessBefore = await dataProtectorCore.grantAccess({
307+
protectedData: protectedData.address,
308+
authorizedApp: sconeAppAddress,
309+
authorizedUser: userAddress,
310+
numberOfAccess: 5,
311+
});
312+
313+
expect(accessBefore).toHaveLength(1);
314+
expect(accessBefore[0].remainingAccess).toBe(5);
315+
316+
// Mock the task processing to avoid actual execution
317+
const mockTaskObservable = {
318+
subscribe: ({ complete }) => {
319+
if (complete) {
320+
setTimeout(complete, 100); // Simulate some processing time
321+
}
322+
return () => {};
323+
},
324+
};
325+
326+
jest.spyOn(iexec.task, 'obsTask').mockResolvedValue(mockTaskObservable as any);
327+
jest.spyOn(iexec.deal, 'computeTaskId').mockResolvedValue('0x123...taskid');
328+
329+
// Mock the order matching to simulate successful order consumption
330+
const mockMatchResult = {
331+
dealid: '0x123...dealid',
332+
txHash: '0x123...txhash',
333+
volume: new BN(1),
334+
};
335+
jest.spyOn(iexec.order, 'matchOrders').mockResolvedValue(mockMatchResult);
336+
337+
// Send 1 email (process the protected data)
338+
try {
339+
await dataProtectorCore.processProtectedData({
340+
protectedData: protectedData.address,
341+
app: sconeAppAddress,
342+
workerpool: workerpoolAddress,
343+
secrets: {
344+
1: 'Test email subject',
345+
2: 'Test email content',
346+
},
347+
args: 'test_args',
348+
});
349+
} catch (error) {
350+
// We expect this to fail due to mocking, but the order should still be consumed
351+
console.log('Expected processing error due to mocking:', error.message);
352+
}
353+
354+
// Check that remaining access shows 4 (not 5)
355+
const { grantedAccess: accessAfter } = await dataProtectorCore.getGrantedAccess({
356+
protectedData: protectedData.address,
357+
authorizedApp: sconeAppAddress,
358+
authorizedUser: userAddress,
359+
});
360+
361+
expect(accessAfter).toHaveLength(1);
362+
expect(accessAfter[0].remainingAccess).toBe(4);
363+
364+
// Restore mocks
365+
jest.restoreAllMocks();
366+
},
367+
4 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
368+
);
369+
});
370+
371+
describe('Re-granting access', () => {
372+
it(
373+
'should add up remaining access when granting access multiple times',
374+
async () => {
375+
// Create a protected data
376+
const protectedData = await dataProtectorCore.protectData({
377+
data: { email: '[email protected]' },
378+
name: 'test protected data for re-granting',
379+
});
380+
381+
const userAddress = await iexec.wallet.getAddress();
382+
383+
// Grant access to yourself with volume = 5
384+
await dataProtectorCore.grantAccess({
385+
protectedData: protectedData.address,
386+
authorizedApp: sconeAppAddress,
387+
authorizedUser: userAddress,
388+
numberOfAccess: 5,
389+
});
390+
391+
// Mock and process 1 email
392+
const mockTaskObservable = {
393+
subscribe: ({ complete }) => {
394+
if (complete) {
395+
setTimeout(complete, 100);
396+
}
397+
return () => {};
398+
},
399+
};
400+
401+
jest.spyOn(iexec.task, 'obsTask').mockResolvedValue(mockTaskObservable as any);
402+
jest.spyOn(iexec.deal, 'computeTaskId').mockResolvedValue('0x124...taskid');
403+
jest.spyOn(iexec.order, 'matchOrders').mockResolvedValue({
404+
dealid: '0x124...dealid',
405+
txHash: '0x124...txhash',
406+
volume: new BN(1),
407+
});
408+
409+
try {
410+
await dataProtectorCore.processProtectedData({
411+
protectedData: protectedData.address,
412+
app: sconeAppAddress,
413+
workerpool: workerpoolAddress,
414+
secrets: {
415+
1: 'Test email subject 2',
416+
2: 'Test email content 2',
417+
},
418+
args: 'test_args_2',
419+
});
420+
} catch (error) {
421+
console.log('Expected processing error due to mocking:', error.message);
422+
}
423+
424+
// Check that remaining access shows 4
425+
const { grantedAccess: accessAfterFirstEmail } = await dataProtectorCore.getGrantedAccess({
426+
protectedData: protectedData.address,
427+
authorizedApp: sconeAppAddress,
428+
authorizedUser: userAddress,
429+
});
430+
431+
expect(accessAfterFirstEmail).toHaveLength(1);
432+
expect(accessAfterFirstEmail[0].remainingAccess).toBe(4);
433+
434+
// Grant access again with volume = 5
435+
await dataProtectorCore.grantAccess({
436+
protectedData: protectedData.address,
437+
authorizedApp: sconeAppAddress,
438+
authorizedUser: userAddress,
439+
numberOfAccess: 5,
440+
});
441+
442+
// Check that remaining access shows 9 (4 + 5)
443+
const { grantedAccess: accessAfterReGrant } = await dataProtectorCore.getGrantedAccess({
444+
protectedData: protectedData.address,
445+
authorizedApp: sconeAppAddress,
446+
authorizedUser: userAddress,
447+
});
448+
449+
expect(accessAfterReGrant).toHaveLength(1);
450+
expect(accessAfterReGrant[0].remainingAccess).toBe(9);
451+
452+
jest.restoreAllMocks();
453+
},
454+
5 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
455+
);
456+
});
457+
458+
describe('Reaching zero', () => {
459+
it(
460+
'should correctly decrement from 2 to 1 to 0 remaining access',
461+
async () => {
462+
// Create a protected data
463+
const protectedData = await dataProtectorCore.protectData({
464+
data: { email: '[email protected]' },
465+
name: 'test protected data for reaching zero',
466+
});
467+
468+
const userAddress = await iexec.wallet.getAddress();
469+
470+
// Grant access to yourself with volume = 2
471+
await dataProtectorCore.grantAccess({
472+
protectedData: protectedData.address,
473+
authorizedApp: sconeAppAddress,
474+
authorizedUser: userAddress,
475+
numberOfAccess: 2,
476+
});
477+
478+
// Check initial state: should show 2 remaining
479+
const { grantedAccess: initialAccess } = await dataProtectorCore.getGrantedAccess({
480+
protectedData: protectedData.address,
481+
authorizedApp: sconeAppAddress,
482+
authorizedUser: userAddress,
483+
});
484+
485+
expect(initialAccess).toHaveLength(1);
486+
expect(initialAccess[0].remainingAccess).toBe(2);
487+
488+
// Mock task processing
489+
const mockTaskObservable = {
490+
subscribe: ({ complete }) => {
491+
if (complete) {
492+
setTimeout(complete, 100);
493+
}
494+
return () => {};
495+
},
496+
};
497+
498+
jest.spyOn(iexec.task, 'obsTask').mockResolvedValue(mockTaskObservable as any);
499+
jest.spyOn(iexec.deal, 'computeTaskId').mockResolvedValue('0x125...taskid');
500+
501+
// Send first email
502+
jest.spyOn(iexec.order, 'matchOrders').mockResolvedValue({
503+
dealid: '0x125...dealid',
504+
txHash: '0x125...txhash',
505+
volume: new BN(1),
506+
});
507+
508+
try {
509+
await dataProtectorCore.processProtectedData({
510+
protectedData: protectedData.address,
511+
app: sconeAppAddress,
512+
workerpool: workerpoolAddress,
513+
secrets: {
514+
1: 'Test email subject 3-1',
515+
2: 'Test email content 3-1',
516+
},
517+
args: 'test_args_3_1',
518+
});
519+
} catch (error) {
520+
console.log('Expected processing error due to mocking:', error.message);
521+
}
522+
523+
// After email 1: should show 1 remaining
524+
const { grantedAccess: accessAfterFirst } = await dataProtectorCore.getGrantedAccess({
525+
protectedData: protectedData.address,
526+
authorizedApp: sconeAppAddress,
527+
authorizedUser: userAddress,
528+
});
529+
530+
expect(accessAfterFirst).toHaveLength(1);
531+
expect(accessAfterFirst[0].remainingAccess).toBe(1);
532+
533+
// Send second email
534+
jest.spyOn(iexec.order, 'matchOrders').mockResolvedValue({
535+
dealid: '0x126...dealid',
536+
txHash: '0x126...txhash',
537+
volume: new BN(1),
538+
});
539+
540+
try {
541+
await dataProtectorCore.processProtectedData({
542+
protectedData: protectedData.address,
543+
app: sconeAppAddress,
544+
workerpool: workerpoolAddress,
545+
secrets: {
546+
1: 'Test email subject 3-2',
547+
2: 'Test email content 3-2',
548+
},
549+
args: 'test_args_3_2',
550+
});
551+
} catch (error) {
552+
console.log('Expected processing error due to mocking:', error.message);
553+
}
554+
555+
// After email 2: should show 0 remaining
556+
const { grantedAccess: accessAfterSecond } = await dataProtectorCore.getGrantedAccess({
557+
protectedData: protectedData.address,
558+
authorizedApp: sconeAppAddress,
559+
authorizedUser: userAddress,
560+
});
561+
562+
expect(accessAfterSecond).toHaveLength(1);
563+
expect(accessAfterSecond[0].remainingAccess).toBe(0);
564+
565+
jest.restoreAllMocks();
566+
},
567+
6 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME
568+
);
569+
});
570+
});
571+
247572
it(
248573
'Throws error when the marketplace is unavailable',
249574
async () => {

0 commit comments

Comments
 (0)