From 5dc7a79b8b8dd476318541fc5ae7bc76919f3da4 Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Tue, 2 Jul 2024 19:48:56 -0300 Subject: [PATCH] tests: add backup e2e scenarios Signed-off-by: Allain Magyar --- .../e2e-tests/features/backup.feature | 25 ++++ .../e2e-tests/src/abilities/WalletSdk.ts | 8 +- .../e2e-tests/src/steps/EdgeAgentSteps.ts | 81 +++++++++++-- .../e2e-tests/src/steps/LifecycleSteps.ts | 3 +- .../src/workflow/EdgeAgentWorkflow.ts | 113 +++++++++++++++++- 5 files changed, 212 insertions(+), 18 deletions(-) create mode 100644 integration-tests/e2e-tests/features/backup.feature diff --git a/integration-tests/e2e-tests/features/backup.feature b/integration-tests/e2e-tests/features/backup.feature new file mode 100644 index 000000000..07309b82a --- /dev/null +++ b/integration-tests/e2e-tests/features/backup.feature @@ -0,0 +1,25 @@ +@backup +Feature: Backup + The Edge Agent should be able to create and restore a backup + + Scenario: Create and restore a backup + Given Edge Agent has created a backup + Then a new SDK can be restored from Edge Agent + + Scenario: Agent without a seed should not be able to restore the backup + Given Edge Agent has created a backup + Then a new SDK cannot be restored from Edge Agent with wrong seed + + Scenario: Restored backup should be functional + Given Cloud Agent is connected to Edge Agent + And Edge Agent has '1' jwt credentials issued by Cloud Agent + And Edge Agent creates '5' peer DIDs + And Edge Agent creates '3' prism DIDs + And Edge Agent has created a backup + Then a new Restored Agent is restored from Edge Agent + And Restored Agent should have the expected values from Edge Agent + And Edge Agent is dismissed + Given Cloud Agent is connected to Restored Agent + And Cloud Agent asks for present-proof + And Restored Agent sends the present-proof + Then Cloud Agent should see the present-proof is verified diff --git a/integration-tests/e2e-tests/src/abilities/WalletSdk.ts b/integration-tests/e2e-tests/src/abilities/WalletSdk.ts index 39af3fbbb..1585082e3 100644 --- a/integration-tests/e2e-tests/src/abilities/WalletSdk.ts +++ b/integration-tests/e2e-tests/src/abilities/WalletSdk.ts @@ -70,7 +70,7 @@ export class WalletSdk extends Ability implements Initialisable, Discardable { } } - async initialise(): Promise { + async createSdk(seed: SDK.Domain.Seed = undefined) { const apollo = new Apollo() this.store = new SDK.Store({ name: [...Array(30)].map(() => Math.random().toString(36)[2]).join(""), @@ -80,7 +80,7 @@ export class WalletSdk extends Ability implements Initialisable, Discardable { }) const pluto = new SDK.Pluto(this.store, apollo) const mediatorDID = Domain.DID.fromString(await WalletSdk.getMediatorDidThroughOob()) - this.sdk = Agent.initialize({ apollo, pluto, mediatorDID }) + this.sdk = Agent.initialize({ seed, apollo, pluto, mediatorDID }) this.sdk.addListener( ListenerKey.MESSAGE, (messages: SDK.Domain.Message[]) => { @@ -89,7 +89,10 @@ export class WalletSdk extends Ability implements Initialisable, Discardable { } } ) + } + async initialise(): Promise { + await this.createSdk() await this.sdk.start() } @@ -114,7 +117,6 @@ class MessageQueue { revocationStack: Message[] = [] receivedMessages: string[] = [] - enqueue(message: Message) { this.queue.push(message) diff --git a/integration-tests/e2e-tests/src/steps/EdgeAgentSteps.ts b/integration-tests/e2e-tests/src/steps/EdgeAgentSteps.ts index e117d025b..17e5bdac9 100644 --- a/integration-tests/e2e-tests/src/steps/EdgeAgentSteps.ts +++ b/integration-tests/e2e-tests/src/steps/EdgeAgentSteps.ts @@ -34,7 +34,26 @@ Given("{actor} has '{int}' anonymous credentials issued by {actor}", await EdgeAgentWorkflow.processIssuedCredential(edgeAgent, recordId) }) await cloudAgent.attemptsTo(Notepad.notes().set("recordIdList", recordIdList)) - }) + } +) + +Given("{actor} has created a backup", + async function(edgeAgent: Actor) { + await EdgeAgentWorkflow.createBackup(edgeAgent) + } +) + +Given("{actor} creates '{}' peer DIDs", + async function(edgeAgent: Actor, numberOfDids: number) { + await EdgeAgentWorkflow.createPeerDids(edgeAgent, numberOfDids) + } +) + +Given("{actor} creates '{}' prism DIDs", + async function(edgeAgent: Actor, numberOfDids: number) { + await EdgeAgentWorkflow.createPrismDids(edgeAgent, numberOfDids) + } +) When("{actor} accepts {int} jwt credential offer sequentially from {actor}", async function (edgeAgent: Actor, numberOfCredentialOffers: number, cloudAgent: Actor) { @@ -48,7 +67,8 @@ When("{actor} accepts {int} jwt credential offer sequentially from {actor}", recordIdList.push(recordId) }) await cloudAgent.attemptsTo(Notepad.notes().set("recordIdList", recordIdList)) - }) + } +) When("{actor} accepts {int} jwt credentials offer at once from {actor}", async function (edgeAgent: Actor, numberOfCredentials: number, cloudAgent: Actor) { @@ -65,12 +85,14 @@ When("{actor} accepts {int} jwt credentials offer at once from {actor}", await Utils.repeat(numberOfCredentials, async () => { await EdgeAgentWorkflow.acceptCredential(edgeAgent) }) - }) + } +) When("{actor} connects through the invite", async function (edgeAgent: Actor) { await EdgeAgentWorkflow.connect(edgeAgent) - }) + } +) When("{actor} accepts the credentials offer from {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { @@ -78,31 +100,36 @@ When("{actor} accepts the credentials offer from {actor}", Utils.repeat(recordIdList.length, async () => { await EdgeAgentWorkflow.acceptCredential(edgeAgent) }) - }) + } +) When("{actor} sends the present-proof", async function (edgeAgent: Actor) { await EdgeAgentWorkflow.waitForProofRequest(edgeAgent) await EdgeAgentWorkflow.presentProof(edgeAgent) - }) + } +) Then("{actor} should receive the credentials offer from {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { const recordIdList = await cloudAgent.answer(Notepad.notes().get("recordIdList")) await EdgeAgentWorkflow.waitForCredentialOffer(edgeAgent, recordIdList.length) - }) + } +) Then("{actor} waits to receive the revocation notifications from {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { const revokedRecordIdList = await cloudAgent.answer(Notepad.notes().get("revokedRecordIdList")) await EdgeAgentWorkflow.waitForCredentialRevocationMessage(edgeAgent, revokedRecordIdList.length) - }) + } +) Then("{actor} should see the credentials were revoked by {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { const revokedRecordIdList = await cloudAgent.answer(Notepad.notes().get("revokedRecordIdList")) await EdgeAgentWorkflow.waitUntilCredentialIsRevoked(edgeAgent, revokedRecordIdList) - }) + } +) Then("{actor} process issued credentials from {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { @@ -110,10 +137,42 @@ Then("{actor} process issued credentials from {actor}", for (const recordId of recordIdList) { await EdgeAgentWorkflow.processIssuedCredential(edgeAgent, recordId) } - }) + } +) Then("{actor} wait to receive issued credentials from {actor}", async function (edgeAgent: Actor, cloudAgent: Actor) { const recordIdList = await cloudAgent.answer(Notepad.notes().get("recordIdList")) await EdgeAgentWorkflow.waitToReceiveCredentialIssuance(edgeAgent, recordIdList.length) - }) + } +) + +Then("a new SDK can be restored from {actor}", + async function(edgeAgent: Actor) { + await EdgeAgentWorkflow.createNewWalletFromBackup(edgeAgent) + } +) + +Then("a new SDK cannot be restored from {actor} with wrong seed", + async function(edgeAgent: Actor) { + await EdgeAgentWorkflow.createNewWalletFromBackupWithWrongSeed(edgeAgent) + } +) + +Then("a new {actor} is restored from {actor}", + async function(newAgent: Actor, edgeAgent: Actor) { + await EdgeAgentWorkflow.backupAndRestoreToNewAgent(newAgent, edgeAgent) + } +) + +Then("{actor} should have the expected values from {actor}", + async function(copyEdgeAgent: Actor, originalEdgeAgent: Actor) { + await EdgeAgentWorkflow.copyAgentShouldMatchOriginalAgent(copyEdgeAgent, originalEdgeAgent) + } +) + +Then("{actor} is dismissed", + async function(edgeAgent: Actor) { + await edgeAgent.dismiss() + } +) diff --git a/integration-tests/e2e-tests/src/steps/LifecycleSteps.ts b/integration-tests/e2e-tests/src/steps/LifecycleSteps.ts index 05e17a709..3f5e71a7c 100644 --- a/integration-tests/e2e-tests/src/steps/LifecycleSteps.ts +++ b/integration-tests/e2e-tests/src/steps/LifecycleSteps.ts @@ -38,7 +38,6 @@ class Actors implements Cast { actors.add(cloudAgent) actors.add(edgeAgent) actors.add(verifierEdgeAgent) - engage(actors) } @@ -48,7 +47,7 @@ class Actors implements Cast { prepare(actor: Actor): Actor { if (!this.actors.has(actor.name)) { - throw new Error(`Unable to find actor ${actor.name}`) + return actor } return this.actors.get(actor.name)! } diff --git a/integration-tests/e2e-tests/src/workflow/EdgeAgentWorkflow.ts b/integration-tests/e2e-tests/src/workflow/EdgeAgentWorkflow.ts index b07485395..0a508b166 100644 --- a/integration-tests/e2e-tests/src/workflow/EdgeAgentWorkflow.ts +++ b/integration-tests/e2e-tests/src/workflow/EdgeAgentWorkflow.ts @@ -1,14 +1,16 @@ import SDK from "@atala/prism-wallet-sdk" -import { Actor, Duration, Notepad, Wait } from "@serenity-js/core" +import { Actor, Duration, Notepad, TakeNotes, Wait } from "@serenity-js/core" import { Ensure, equals } from "@serenity-js/assertions" import { WalletSdk } from "../abilities/WalletSdk" import { Utils } from "../Utils" +import { randomUUID } from "crypto" +import _ from "lodash" +import { assert } from "chai" const { IssueCredential, OfferCredential, RequestPresentation, } = SDK export class EdgeAgentWorkflow { - static async connect(edgeAgent: Actor) { const url = await edgeAgent.answer(Notepad.notes().get("invitation")) await edgeAgent.attemptsTo( @@ -120,4 +122,111 @@ export class EdgeAgentWorkflow { }) ) } + + static async createPeerDids(edgeAgent: Actor, numberOfDids: number) { + await edgeAgent.attemptsTo( + WalletSdk.execute(async sdk => { + await Utils.repeat(numberOfDids, async () => { + await sdk.createNewPeerDID() + }) + }) + ) + } + + static async createPrismDids(edgeAgent: Actor, numberOfDids: number) { + await edgeAgent.attemptsTo( + WalletSdk.execute(async sdk => { + await Utils.repeat(numberOfDids, async () => { + await sdk.createNewPrismDID(randomUUID()) + }) + }) + ) + } + + static async copyAgentShouldMatchOriginalAgent(copyEdgeAgent: Actor, originalEdgeAgent: Actor) { + let expectedCredentials: SDK.Domain.Credential[] + let expectedPeerDids: SDK.PeerDID[] + let expectedPrismDids: SDK.Domain.PrismDID[] + let expectedDidPairs: SDK.Domain.DIDPair[] + + await originalEdgeAgent.attemptsTo( + WalletSdk.execute(async sdk => { + expectedCredentials = await sdk.verifiableCredentials() + expectedPeerDids = await sdk.pluto.getAllPeerDIDs() + expectedPrismDids = await sdk.pluto.getAllPrismDIDs() + expectedDidPairs = await sdk.pluto.getAllDidPairs() + }) + ) + + await copyEdgeAgent.attemptsTo( + WalletSdk.execute(async sdk => { + const credentials = await sdk.verifiableCredentials() + const peerDids = await sdk.pluto.getAllPeerDIDs() + const prismDids = await sdk.pluto.getAllPrismDIDs() + const didPairs = await sdk.pluto.getAllDidPairs() + + await copyEdgeAgent.attemptsTo( + Ensure.that(credentials.length, equals(expectedCredentials.length)), + Ensure.that(peerDids.length, equals(expectedPeerDids.length)), + Ensure.that(prismDids.length, equals(expectedPrismDids.length)), + Ensure.that(didPairs.length, equals(expectedDidPairs.length)), + ) + + assert.isTrue(_.isEqual(expectedCredentials.map(it => it.id), credentials.map(it => it.id))) + assert.isTrue(_.isEqual(expectedPeerDids.map(it => it.did.uuid), peerDids.map(it => it.did.uuid))) + assert.isTrue(_.isEqual(expectedPrismDids.map(it => it.did.uuid), prismDids.map(it => it.did.uuid))) + assert.isTrue(_.isEqual(expectedDidPairs.map(it => it.name), expectedDidPairs.map(it => it.name))) + }) + ) + } + + + static async createBackup(edgeAgent: Actor) { + await edgeAgent.attemptsTo( + WalletSdk.execute(async (sdk) => { + const backup = await sdk.backup.createJWE() + await edgeAgent.attemptsTo( + Notepad.notes().set("backup", backup), + Notepad.notes().set("seed", sdk.seed) + ) + }) + ) + } + + static async createNewWalletFromBackup(edgeAgent: Actor) { + const backup = await edgeAgent.answer(Notepad.notes().get("backup")) + const seed = await edgeAgent.answer(Notepad.notes().get("seed")) + const walletSdk = new WalletSdk() + await walletSdk.createSdk(seed) + await walletSdk.sdk.pluto.start() + await walletSdk.sdk.backup.restore(backup) + await walletSdk.sdk.start() + await walletSdk.sdk.stop() + } + + static async createNewWalletFromBackupWithWrongSeed(edgeAgent: Actor) { + const backup = await edgeAgent.answer(Notepad.notes().get("backup")) + const walletSdk = new WalletSdk() + const seed = new SDK.Apollo().createRandomSeed().seed + await walletSdk.createSdk(seed) + await walletSdk.sdk.pluto.start() + + try { + await walletSdk.sdk.backup.restore(backup) + assert.fail("SDK should not be able to restore with wrong seed phrase.") + } catch (e) { + assert.isTrue(e != undefined) + } + } + + static async backupAndRestoreToNewAgent(newAgent: Actor, edgeAgent: Actor) { + const backup = await edgeAgent.answer(Notepad.notes().get("backup")) + const seed = await edgeAgent.answer(Notepad.notes().get("seed")) + const walletSdk = new WalletSdk() + await walletSdk.createSdk(seed) + await walletSdk.sdk.pluto.start() + await walletSdk.sdk.backup.restore(backup) + await walletSdk.sdk.start() + newAgent.whoCan(walletSdk, TakeNotes.usingAnEmptyNotepad()) + } }