From b42323824e26ce46eb6094ea75e4cf29436669a9 Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Fri, 22 Sep 2023 14:20:09 -0300 Subject: [PATCH] test: new e2e scenarios (#101) --- .github/workflows/e2e-tests.yml | 9 ++- tests/end-to-end/build.gradle.kts | 4 +- tests/end-to-end/serenity.properties | 1 + .../kotlin/io/iohk/atala/prism/TestSuite.kt | 8 +++ .../atala/prism/abilities/UseWalletSdk.kt | 7 +- .../atala/prism/configuration/Environment.kt | 24 ++++--- .../iohk/atala/prism/steps/CloudAgentSteps.kt | 11 ++- .../iohk/atala/prism/steps/EdgeAgentSteps.kt | 71 +++++++++++++++++-- .../prism/workflow/CloudAgentWorkflow.kt | 5 +- .../atala/prism/workflow/EdgeAgentWorkflow.kt | 26 +++---- .../features/credential/Credential.feature | 27 ++++--- .../present-proof/PresentProof.feature | 9 +++ .../src/test/resources/features/readme.md | 22 ------ 13 files changed, 153 insertions(+), 71 deletions(-) create mode 100644 tests/end-to-end/src/test/resources/features/present-proof/PresentProof.feature diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index ef2f8556f..169430d1c 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -12,11 +12,11 @@ on: mediatorOobUrl: required: true description: Mediator out-of-band url - default: https://mediator.rootsid.cloud/oob_url + default: https://sit-prism-mediator.atalaprism.io/invitationOOB prismAgentUrl: required: true description: Prism-agent server url - default: https://k8s-dev.atalaprism.io/prism-agent + default: https://sit-prism-agent-issuer.atalaprism.io/prism-agent publishedDid: required: false description: Published DID @@ -29,6 +29,9 @@ on: pull_request: branches: - main + push: + branches: + - main env: ATALA_GITHUB_ACTOR: ${{ secrets.ATALA_GITHUB_ACTOR }} @@ -79,6 +82,6 @@ jobs: - name: Publish Serenity report uses: actions/upload-artifact@v3 with: - name: atala-prism-sdk-kmm.zip + name: atala-prism-sdk-kmm path: tests/end-to-end/target/site/serenity if-no-files-found: error diff --git a/tests/end-to-end/build.gradle.kts b/tests/end-to-end/build.gradle.kts index e8038fb8a..6928e2e14 100644 --- a/tests/end-to-end/build.gradle.kts +++ b/tests/end-to-end/build.gradle.kts @@ -3,14 +3,13 @@ plugins { idea java id("com.github.ben-manes.versions") version "0.47.0" - id("net.serenity-bdd.serenity-gradle-plugin") version "3.7.0" + id("net.serenity-bdd.serenity-gradle-plugin") version "4.0.1" } group = "io.iohk.atala.prism" version = "1.0-SNAPSHOT" repositories { - mavenLocal() mavenCentral() maven { url = uri("https://maven.pkg.github.com/input-output-hk/atala-automation/") @@ -19,6 +18,7 @@ repositories { password = System.getenv("ATALA_GITHUB_TOKEN") } } + mavenLocal() } dependencies { diff --git a/tests/end-to-end/serenity.properties b/tests/end-to-end/serenity.properties index 9c7a9e0e3..3b12a41ae 100644 --- a/tests/end-to-end/serenity.properties +++ b/tests/end-to-end/serenity.properties @@ -5,3 +5,4 @@ serenity.simplified.stack.traces=false serenity.report.accessibility=true json.pretty.printing=true serenity.console.headings=normal +serenity.console.colors=true diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/TestSuite.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/TestSuite.kt index 3d6f84a74..1cbd0db80 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/TestSuite.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/TestSuite.kt @@ -1,6 +1,8 @@ package io.iohk.atala.prism +import io.cucumber.java.BeforeAll import io.cucumber.junit.CucumberOptions +import io.iohk.atala.prism.configuration.Environment import net.serenitybdd.cucumber.CucumberWithSerenity import org.junit.runner.RunWith @@ -10,3 +12,9 @@ import org.junit.runner.RunWith plugin = ["pretty"] ) class TestSuite + +// https://cucumber.io/docs/cucumber/api/?lang=kotlin +@BeforeAll +fun setupEnvironment() { + Environment.setup() +} diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/abilities/UseWalletSdk.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/abilities/UseWalletSdk.kt index 74fcb6863..1a234ef92 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/abilities/UseWalletSdk.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/abilities/UseWalletSdk.kt @@ -81,6 +81,7 @@ class UseWalletSdk : Ability { private val logger = Logger.get() private val context: SdkContext + private val receivedMessages = mutableListOf() init { val apollo = ApolloImpl() @@ -119,6 +120,10 @@ class UseWalletSdk : Ability { CoroutineScope(Dispatchers.Default).launch { sdk.handleReceivedMessagesEvents().collect { messageList: List -> messageList.forEach { message -> + if (receivedMessages.contains(message.id)) { + return@forEach + } + receivedMessages.add(message.id) when (message.piuri) { ProtocolType.DidcommOfferCredential.value -> context.credentialOfferStack.add(message) ProtocolType.DidcommIssueCredential.value -> context.issuedCredentialStack.add(message) @@ -148,4 +153,4 @@ data class SdkContext( ) class ActorCannotUseWalletSdk(actor: Actor) : - Throwable("The actor [${actor.name}] does not have the ability to use wallet-sdk") \ No newline at end of file + Throwable("The actor [${actor.name}] does not have the ability to use wallet-sdk") diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/configuration/Environment.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/configuration/Environment.kt index 74dcec0a4..dd155107c 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/configuration/Environment.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/configuration/Environment.kt @@ -10,21 +10,22 @@ import io.restassured.response.Response import net.serenitybdd.rest.SerenityRest import org.apache.http.HttpStatus import org.assertj.core.api.Assertions +import java.io.File import java.util.* import kotlin.time.Duration.Companion.seconds object Environment { private val logger = Logger.get() - val agentUrl: String - val mediatorOobUrl: String + lateinit var agentUrl: String + lateinit var mediatorOobUrl: String lateinit var publishedDid: String lateinit var schemaId: String /** * Set up the variables based on the properties config file */ - init { + fun setup() { // prepare notes Notes.prepareNotes() @@ -58,6 +59,14 @@ object Environment { Notes.appendMessage("Agent: $agentUrl") Notes.appendMessage("DID: $publishedDid") Notes.appendMessage("Schema: $schemaId") + Notes.appendMessage("SDK Version: ${getSdkVersion()}") + } + + private fun getSdkVersion(): String { + val file = File("build.gradle.kts") + val input = file.readText() + val regex = Regex("prism-sdk:(.*)(?=\")") + return regex.find(input)!!.groups[1]!!.value } /** @@ -74,7 +83,7 @@ object Environment { this.publishedDid = publishedDid!! return } catch (e: AssertionError) { - logger.warn("DID not found. Creating a new one.") + Notes.appendMessage("DID [${publishedDid}] not found. Creating a new one.") } val publicKey = ManagedDIDKeyTemplate( @@ -113,14 +122,12 @@ object Environment { response.body.jsonPath().getString("status") == "PUBLISHED" } this.publishedDid = response.body.jsonPath().getString("did") - - Notes.appendMessage("Created new DID: ${this.publishedDid}") } /** * Checks if the environment SCHEMA_ID variable exists in prism-agent, otherwise it creates a new one. */ - fun checkSchema(schemaId: String?) { + private fun checkSchema(schemaId: String?) { try { RestAssured .given() @@ -131,7 +138,7 @@ object Environment { this.schemaId = schemaId!! return } catch (e: AssertionError) { - logger.warn("Schema not found. Creating a new one.") + Notes.appendMessage("Schema [${schemaId}] not found. Creating a new one.") } val schemaName = "automation-schema-" + UUID.randomUUID() @@ -161,7 +168,6 @@ object Environment { .thenReturn() this.schemaId = schemaCreationResponse.body.jsonPath().getString("guid") - Notes.appendMessage("Created new schema: ${this.schemaId}") } } diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/CloudAgentSteps.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/CloudAgentSteps.kt index 5bc52c4bb..db88bc71a 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/CloudAgentSteps.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/CloudAgentSteps.kt @@ -41,7 +41,8 @@ class CloudAgentSteps { @When("{actor} should see the credential was accepted") fun `Cloud Agent should see the credential was accepted`(cloudAgent: Actor) { - cloudAgentWorkflow.verifyCredentialState(cloudAgent, "CredentialSent") + val recordId = cloudAgent.recall("recordId") + cloudAgentWorkflow.verifyCredentialState(cloudAgent, recordId, "CredentialSent") } @When("{actor} asks for present-proof") @@ -58,4 +59,12 @@ class CloudAgentSteps { fun `Cloud Agent should see the present-proof is verified`(cloudAgent: Actor) { cloudAgentWorkflow.verifyPresentProof(cloudAgent, "PresentationVerified") } + + @Then("{actor} should see all credentials were accepted") + fun `Cloud Agent should see all credentials were accepted`(cloudAgent: Actor) { + val recordIdList = cloudAgent.recall>("recordIdList") + for (recordId in recordIdList) { + cloudAgentWorkflow.verifyCredentialState(cloudAgent, recordId, "CredentialSent") + } + } } diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/EdgeAgentSteps.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/EdgeAgentSteps.kt index 88f55fd18..c3c6af4a7 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/EdgeAgentSteps.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/steps/EdgeAgentSteps.kt @@ -4,6 +4,7 @@ import io.cucumber.java.After import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.prism.abilities.UseWalletSdk +import io.iohk.atala.prism.workflow.CloudAgentWorkflow import io.iohk.atala.prism.workflow.EdgeAgentWorkflow import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.actors.OnStage @@ -14,11 +15,67 @@ class EdgeAgentSteps { @Inject private lateinit var edgeAgentWorkflow: EdgeAgentWorkflow + @Inject + private lateinit var cloudAgentWorkflow: CloudAgentWorkflow + @When("{actor} connects through the invite") fun `Edge Agent connects through the invite`(edgeAgent: Actor) { edgeAgentWorkflow.connect(edgeAgent) } + @When("{actor} has {} credentials issued by {actor}") + fun `Edge Agent has {} issued credential`(edgeAgent: Actor, numberOfCredentialsIssued: Int, cloudAgent: Actor) { + repeat(numberOfCredentialsIssued) { + cloudAgentWorkflow.offerCredential(cloudAgent) + edgeAgentWorkflow.waitForCredentialOffer(edgeAgent, 1) + edgeAgentWorkflow.acceptCredential(edgeAgent) + cloudAgentWorkflow.verifyCredentialState(cloudAgent, cloudAgent.recall("recordId"), "CredentialSent") + edgeAgentWorkflow.waitToReceiveCredentialIssuance(edgeAgent, 1) + edgeAgentWorkflow.processIssuedCredential(edgeAgent, 1) + } + } + + @When("{actor} accepts {} credential offer sequentially from {actor}") + fun `Edge Agent accepts multiple credentials offer sequentially from Cloud Agent`( + edgeAgent: Actor, + numberOfCredentials: Int, + cloudAgent: Actor + ) { + val recordIdList = mutableListOf() + repeat(numberOfCredentials) { + cloudAgentWorkflow.offerCredential(cloudAgent) + edgeAgentWorkflow.waitForCredentialOffer(edgeAgent, 1) + edgeAgentWorkflow.acceptCredential(edgeAgent) + cloudAgentWorkflow.verifyCredentialState(cloudAgent, cloudAgent.recall("recordId"), "CredentialSent") + recordIdList.add(cloudAgent.recall("recordId")) + } + cloudAgent.remember("recordIdList", recordIdList) + } + + @When("{actor} accepts {} credentials offer at once from {actor}") + fun `Edge Agent accepts multiple credentials offer at once from Cloud Agent`( + edgeAgent: Actor, + numberOfCredentials: Int, + cloudAgent: Actor + ) { + val recordIdList = mutableListOf() + + // offer multiple credentials + repeat(numberOfCredentials) { + cloudAgentWorkflow.offerCredential(cloudAgent) + recordIdList.add(cloudAgent.recall("recordId")) + } + cloudAgent.remember("recordIdList", recordIdList) + + // wait to receive + edgeAgentWorkflow.waitForCredentialOffer(edgeAgent, numberOfCredentials) + + // accept all + repeat(numberOfCredentials) { + edgeAgentWorkflow.acceptCredential(edgeAgent) + } + } + @When("{actor} accepts the credential") fun `Edge Agent accepts the credential`(edgeAgent: Actor) { edgeAgentWorkflow.acceptCredential(edgeAgent) @@ -32,17 +89,17 @@ class EdgeAgentSteps { @Then("{actor} should receive the credential") fun `Edge Agent should receive the credential`(edgeAgent: Actor) { - edgeAgentWorkflow.waitForCredentialOffer(edgeAgent) + edgeAgentWorkflow.waitForCredentialOffer(edgeAgent, 1) } - @Then("{actor} wait to receive an issued credential") - fun `Edge Agent wait to receive an issued credential`(edgeAgent: Actor) { - edgeAgentWorkflow.waitToReceiveIssuedCredential(edgeAgent) + @Then("{actor} wait to receive {} issued credentials") + fun `Edge Agent wait to receive issued credentials`(edgeAgent: Actor, expectedNumberOfCredentials: Int) { + edgeAgentWorkflow.waitToReceiveCredentialIssuance(edgeAgent, expectedNumberOfCredentials) } - @Then("{actor} process the issued credential") - fun `Edge Agent process the issued credential`(edgeAgent: Actor) { - edgeAgentWorkflow.processIssuedCredential(edgeAgent) + @Then("{actor} process {} issued credentials") + fun `Edge Agent process multiple issued credentials`(edgeAgent: Actor, numberOfCredentials: Int) { + edgeAgentWorkflow.processIssuedCredential(edgeAgent, numberOfCredentials) } @After diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/CloudAgentWorkflow.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/CloudAgentWorkflow.kt index 5eed0da5e..d1c6b3bec 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/CloudAgentWorkflow.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/CloudAgentWorkflow.kt @@ -44,7 +44,7 @@ class CloudAgentWorkflow { fun offerCredential(cloudAgent: Actor) { val connectionId = cloudAgent.recall("connectionId") val credential = CreateIssueCredentialRecordRequest( - claims = mapOf(Pair("automation-required", "required value")), + claims = mapOf(Pair("automation-required", UUID.randomUUID())), issuingDID = Environment.publishedDid, connectionId = connectionId, schemaId = "${Environment.agentUrl}/schema-registry/schemas/${Environment.schemaId}" @@ -79,8 +79,7 @@ class CloudAgentWorkflow { cloudAgent.remember("presentationId", lastResponse().get("presentationId")) } - fun verifyCredentialState(cloudAgent: Actor, state: String) { - val recordId = cloudAgent.recall("recordId") + fun verifyCredentialState(cloudAgent: Actor, recordId: String, state: String) { cloudAgent.attemptsTo( PollingWait.until( HttpRequest.get("/issue-credentials/records/$recordId"), diff --git a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/EdgeAgentWorkflow.kt b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/EdgeAgentWorkflow.kt index 7d8b976ba..b87f4f3a1 100644 --- a/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/EdgeAgentWorkflow.kt +++ b/tests/end-to-end/src/test/kotlin/io/iohk/atala/prism/workflow/EdgeAgentWorkflow.kt @@ -65,37 +65,33 @@ class EdgeAgentWorkflow { ) } - fun waitForCredentialOffer(edgeAgent: Actor) { + fun waitForCredentialOffer(edgeAgent: Actor, numberOfCredentialOffer: Int) { edgeAgent.attemptsTo( PollingWait.until( UseWalletSdk.credentialOfferStackSize(), - equalTo(1) + equalTo(numberOfCredentialOffer) ) ) } - fun waitToReceiveIssuedCredential(edgeAgent: Actor) { + fun waitToReceiveCredentialIssuance(edgeAgent: Actor, expectedNumberOfCredentials: Int) { edgeAgent.attemptsTo( PollingWait.until( UseWalletSdk.issuedCredentialStackSize(), - equalTo(1) + equalTo(expectedNumberOfCredentials) ) ) } - fun processIssuedCredential(edgeAgent: Actor) { + fun processIssuedCredential(edgeAgent: Actor, numberOfCredentials: Int) { edgeAgent.attemptsTo( - UseWalletSdk.execute { - val issuedCredentialMessage = it.issuedCredentialStack.removeFirst() - val issuedCredential = IssueCredential.fromMessage(issuedCredentialMessage) - it.sdk.processIssuedCredentialMessage(issuedCredential) + UseWalletSdk.execute { sdkContext -> + repeat(numberOfCredentials) { + val issuedCredentialMessage = sdkContext.issuedCredentialStack.removeFirst() + val issuedCredential = IssueCredential.fromMessage(issuedCredentialMessage) + sdkContext.sdk.processIssuedCredentialMessage(issuedCredential) + } } ) } - - fun stopSdk(edgeAgent: Actor) { - edgeAgent.attemptsTo( - UseWalletSdk.stop() - ) - } } diff --git a/tests/end-to-end/src/test/resources/features/credential/Credential.feature b/tests/end-to-end/src/test/resources/features/credential/Credential.feature index ce937cfd8..f2cd02159 100644 --- a/tests/end-to-end/src/test/resources/features/credential/Credential.feature +++ b/tests/end-to-end/src/test/resources/features/credential/Credential.feature @@ -1,14 +1,25 @@ -Feature: Credential and present-proof - The Edge Agent should be able to receive a credential from Cloud Agent and respond to a proof-of-request +Feature: Receive verifiable credential + The Edge Agent should be able to receive a verifiable credential from Cloud Agent - Scenario: Accept credential and respond to present-proof + Scenario: Receive one verifiable credential Given Cloud Agent is connected to Edge Agent When Cloud Agent offers a credential Then Edge Agent should receive the credential When Edge Agent accepts the credential And Cloud Agent should see the credential was accepted - Then Edge Agent wait to receive an issued credential - And Edge Agent process the issued credential - When Cloud Agent asks for present-proof - And Edge Agent sends the present-proof - Then Cloud Agent should see the present-proof is verified + Then Edge Agent wait to receive 1 issued credentials + And Edge Agent process 1 issued credentials + + Scenario: Receive multiple verifiable credentials sequentially + Given Cloud Agent is connected to Edge Agent + When Edge Agent accepts 3 credential offer sequentially from Cloud Agent + Then Cloud Agent should see all credentials were accepted + And Edge Agent wait to receive 3 issued credentials + And Edge Agent process 3 issued credentials + + Scenario: Receive multiple verifiable credentials at once + Given Cloud Agent is connected to Edge Agent + When Edge Agent accepts 3 credentials offer at once from Cloud Agent + Then Cloud Agent should see all credentials were accepted + And Edge Agent wait to receive 3 issued credentials + And Edge Agent process 3 issued credentials diff --git a/tests/end-to-end/src/test/resources/features/present-proof/PresentProof.feature b/tests/end-to-end/src/test/resources/features/present-proof/PresentProof.feature new file mode 100644 index 000000000..28bceda04 --- /dev/null +++ b/tests/end-to-end/src/test/resources/features/present-proof/PresentProof.feature @@ -0,0 +1,9 @@ +Feature: Respond to request proof + The Edge Agent should be able to respond to a proof-of-request + + Scenario: Respond to request proof + Given Cloud Agent is connected to Edge Agent + And Edge Agent has 1 credentials issued by Cloud Agent + When Cloud Agent asks for present-proof + And Edge Agent sends the present-proof + Then Cloud Agent should see the present-proof is verified diff --git a/tests/end-to-end/src/test/resources/features/readme.md b/tests/end-to-end/src/test/resources/features/readme.md index 1f696332a..92bfd96d1 100644 --- a/tests/end-to-end/src/test/resources/features/readme.md +++ b/tests/end-to-end/src/test/resources/features/readme.md @@ -4,25 +4,3 @@ End-to-end tests - [Repository](https://github.com/input-output-hk/atala-prism-wallet-sdk-kmm) - [Documentation](https://input-output-hk.github.io/atala-prism-wallet-sdk-kmm/) - -## Environment variables - -To define the environment to be tested we can set the `env` environment variable. - -The default values for each environment are defined in `resources/environment` folder. - -### Possible values - -| env | Description | -|-------|-----------------------------------------------------------------------------------------------------------| -| local | Local tests ran with `local-prism` | -| dev | Development environment. Some of the variables are not set since the database can be constantly wiped | -| sit | Integration environment. Most of the variables should be set since it should be a more stable environment | - -### Overriding environment variables - -| Attribute | Description | Environment default | -|----------------|-----------------------------------------------------------------------------------------------|---------------------| -| mediatorOobUrl | OOB invitation for mediator | local; dev; sit | -| agentUrl | Prism-agent url | local; dev; sit | -| publicatedDid | Did published. If the variable is not provided the automation will create a new published DID | sit |