From 8684124189912131694de2b35b199211cf24cdf0 Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Tue, 7 May 2024 11:59:30 -0300 Subject: [PATCH] test: finish fixing jwt revocation Signed-off-by: Allain Magyar --- .../src/test/kotlin/common/Utils.kt | 28 ---- .../test/kotlin/steps/common/CommonSteps.kt | 2 +- .../steps/connection/ConnectionSteps.kt | 45 +++--- .../credentials/IssueCredentialsSteps.kt | 141 +++++----------- .../credentials/RevokeCredentialSteps.kt | 14 +- .../kotlin/steps/did/DeactivateDidSteps.kt | 23 ++- .../test/kotlin/steps/did/PublishDidSteps.kt | 72 +++------ .../test/kotlin/steps/did/UpdateDidSteps.kt | 150 ++++++++---------- .../proofs/AnoncredsPresentProofSteps.kt | 41 ++--- .../kotlin/steps/proofs/PresentProofSteps.kt | 2 +- .../schemas/AnoncredCredentialSchemaSteps.kt | 85 ++++++++++ .../credentials/issue_credentials.feature | 36 ----- .../credentials/issue_published_did.feature | 5 +- .../features/did/deactivate_did.feature | 5 +- .../resources/features/did/update_did.feature | 2 +- .../features/proofs/present_proof.feature | 1 + .../proofs/present_proof_anoncred.feature | 6 +- ....feature => revoke_jwt_credential.feature} | 3 +- 18 files changed, 280 insertions(+), 381 deletions(-) delete mode 100644 tests/integration-tests/src/test/kotlin/common/Utils.kt create mode 100644 tests/integration-tests/src/test/kotlin/steps/schemas/AnoncredCredentialSchemaSteps.kt delete mode 100644 tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature rename tests/integration-tests/src/test/resources/features/revocation/{jwt.feature => revoke_jwt_credential.feature} (90%) diff --git a/tests/integration-tests/src/test/kotlin/common/Utils.kt b/tests/integration-tests/src/test/kotlin/common/Utils.kt deleted file mode 100644 index 627dab4357..0000000000 --- a/tests/integration-tests/src/test/kotlin/common/Utils.kt +++ /dev/null @@ -1,28 +0,0 @@ -package common - -import org.awaitility.Awaitility -import org.awaitility.core.ConditionTimeoutException -import org.awaitility.pollinterval.FixedPollInterval -import java.time.Duration - -object Utils { - fun wait( - blockToWait: () -> Boolean, - errorMessage: String, - poolInterval: FixedPollInterval = FixedPollInterval(Duration.ofMillis(500L)), - timeout: Duration = Duration.ofSeconds(120L), - ) { - try { - Awaitility.await().with().pollInterval(poolInterval) - .pollInSameThread() - .atMost(timeout) - .until { - blockToWait() - } - } catch (err: ConditionTimeoutException) { - throw ConditionTimeoutException( - errorMessage, - ) - } - } -} diff --git a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt index 71ad989252..7531829360 100644 --- a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt @@ -29,7 +29,7 @@ class CommonSteps { val publishDidSteps = PublishDidSteps() publishDidSteps.createsUnpublishedDid(holder) - publishDidSteps.actorHavePublishedPrismDid(issuer) + publishDidSteps.agentHasAPublishedDID(issuer) val issueSteps = IssueCredentialsSteps() issueSteps.issuerOffersACredential(issuer, holder, "short") diff --git a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt index e4a3dfc252..e34af92256 100644 --- a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt @@ -1,21 +1,19 @@ package steps.connection import abilities.ListenToEvents -import common.Utils.wait import interactions.Get import interactions.Post import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.automation.utils.Wait import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.SC_CREATED import org.apache.http.HttpStatus.SC_OK import org.assertj.core.api.Assertions.assertThat -import org.hyperledger.identus.client.models.AcceptConnectionInvitationRequest -import org.hyperledger.identus.client.models.Connection -import org.hyperledger.identus.client.models.CreateConnectionRequest +import org.hyperledger.identus.client.models.* class ConnectionSteps { @@ -66,7 +64,8 @@ class ConnectionSteps { Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), Ensure.that(inviteeConnection.invitation.from).isEqualTo(inviterConnection.invitation.from), Ensure.that(inviteeConnection.invitation.id).isEqualTo(inviterConnection.invitation.id), - Ensure.that(inviteeConnection.invitation.invitationUrl).isEqualTo(inviterConnection.invitation.invitationUrl), + Ensure.that(inviteeConnection.invitation.invitationUrl) + .isEqualTo(inviterConnection.invitation.invitationUrl), Ensure.that(inviteeConnection.invitation.type).isEqualTo(inviterConnection.invitation.type), Ensure.that(inviteeConnection.state).isEqualTo(Connection.State.CONNECTION_REQUEST_PENDING), Ensure.that(inviteeConnection.role).isEqualTo(Connection.Role.INVITEE), @@ -77,31 +76,27 @@ class ConnectionSteps { @When("{actor} receives the connection request and sends back the response") fun inviterReceivesTheConnectionRequest(inviter: Actor) { - wait( - { - val lastEvent = ListenToEvents.with(inviter).connectionEvents.lastOrNull { - it.data.thid == inviter.recall("connection").thid - } - lastEvent != null && - lastEvent.data.state == Connection.State.CONNECTION_RESPONSE_SENT - }, - "Inviter connection didn't reach ${Connection.State.CONNECTION_RESPONSE_SENT} state", - ) + Wait.until( + errorMessage = "Inviter connection didn't reach ${Connection.State.CONNECTION_RESPONSE_SENT} state" + ) { + val lastEvent = ListenToEvents.with(inviter).connectionEvents.lastOrNull { + it.data.thid == inviter.recall("connection").thid + } + lastEvent != null && lastEvent.data.state == Connection.State.CONNECTION_RESPONSE_SENT + } } @When("{actor} receives the connection response") fun inviteeReceivesTheConnectionResponse(invitee: Actor) { - // Bob (Holder) receives final connection response - wait( - { - val lastEvent = ListenToEvents.with(invitee).connectionEvents.lastOrNull { - it.data.thid == invitee.recall("connection").thid - } - lastEvent != null && + Wait.until( + errorMessage = "Invitee connection didn't reach ${Connection.State.CONNECTION_RESPONSE_RECEIVED} state." + ) { + val lastEvent = ListenToEvents.with(invitee).connectionEvents.lastOrNull { + it.data.thid == invitee.recall("connection").thid + } + lastEvent != null && lastEvent.data.state == Connection.State.CONNECTION_RESPONSE_RECEIVED - }, - "Invitee connection didn't reach ${Connection.State.CONNECTION_RESPONSE_RECEIVED} state.", - ) + } } @Then("{actor} and {actor} have a connection") diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt index cab839aab6..0e49727a40 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt @@ -2,20 +2,17 @@ package steps.credentials import abilities.ListenToEvents import common.CredentialSchema -import common.Utils.wait import interactions.Post import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure -import models.AnoncredsSchema +import io.iohk.atala.automation.utils.Wait import models.CredentialEvent import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.rest.abilities.CallAnApi import org.apache.http.HttpStatus.* import org.hyperledger.identus.client.models.* -import java.util.UUID class IssueCredentialsSteps { @@ -108,65 +105,7 @@ class IssueCredentialsSteps { "name" to "Name", "surname" to "Surname", ) - sendCredentialOffer(issuer, holder, "short", schemaGuid, claims) - } - - @When("{actor} creates anoncred schema") - fun acmeCreatesAnoncredSchema(issuer: Actor) { - issuer.attemptsTo( - Post.to("/schema-registry/schemas") - .with { - it.body( - CredentialSchemaInput( - author = issuer.recall("shortFormDid"), - name = UUID.randomUUID().toString(), - description = "Simple student credentials schema", - type = "AnoncredSchemaV1", - schema = AnoncredsSchema( - name = "StudentCredential", - version = "1.0", - issuerId = issuer.recall("shortFormDid"), - attrNames = listOf("name", "age", "sex"), - ), - tags = listOf("school", "students"), - version = "1.0.0", - ), - ) - }, - ) - issuer.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), - ) - val schema = SerenityRest.lastResponse().get() - issuer.remember("anoncredsSchema", schema) - } - - @When("{actor} creates anoncred credential definition") - fun acmeCreatesAnoncredCredentialDefinition(issuer: Actor) { - val schemaRegistryUrl = issuer.usingAbilityTo(CallAnApi::class.java).resolve("/schema-registry/schemas") - .replace("localhost", "host.docker.internal") - issuer.attemptsTo( - Post.to("/credential-definition-registry/definitions") - .with { - it.body( - CredentialDefinitionInput( - name = "StudentCredential", - version = "1.0.0", - schemaId = "$schemaRegistryUrl/${issuer.recall("anoncredsSchema").guid}/schema", - description = "Simple student credentials definition", - author = issuer.recall("shortFormDid"), - signatureType = "CL", - tag = "student", - supportRevocation = false, - ), - ) - }, - ) - issuer.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), - ) - val credentialDefinition = SerenityRest.lastResponse().get() - issuer.remember("anoncredsCredentialDefinition", credentialDefinition) + sendCredentialOffer(issuer, holder, format, schemaGuid, claims) } @When("{actor} offers anoncred to {actor}") @@ -204,17 +143,16 @@ class IssueCredentialsSteps { @When("{actor} receives the credential offer") fun holderReceivesCredentialOffer(holder: Actor) { - wait( - { - credentialEvent = ListenToEvents.with(holder).credentialEvents.lastOrNull { - it.data.thid == holder.recall("thid") - } - credentialEvent != null && + Wait.until( + errorMessage = "Holder was unable to receive the credential offer from Issuer! " + + "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.OFFER_RECEIVED} state.", + ) { + credentialEvent = ListenToEvents.with(holder).credentialEvents.lastOrNull { + it.data.thid == holder.recall("thid") + } + credentialEvent != null && credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.OFFER_RECEIVED - }, - "Holder was unable to receive the credential offer from Issuer! " + - "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.OFFER_RECEIVED} state.", - ) + } val recordId = ListenToEvents.with(holder).credentialEvents.last().data.recordId holder.remember("recordId", recordId) @@ -252,16 +190,15 @@ class IssueCredentialsSteps { @When("{actor} issues the credential") fun acmeIssuesTheCredential(issuer: Actor) { - wait( - { - credentialEvent = ListenToEvents.with(issuer).credentialEvents.lastOrNull { - it.data.thid == issuer.recall("thid") - } - credentialEvent != null && + Wait.until( + errorMessage = "Issuer was unable to receive the credential request from Holder! Protocol state did not achieve RequestReceived state." + ) { + credentialEvent = ListenToEvents.with(issuer).credentialEvents.lastOrNull { + it.data.thid == issuer.recall("thid") + } + credentialEvent != null && credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.REQUEST_RECEIVED - }, - "Issuer was unable to receive the credential request from Holder! Protocol state did not achieve RequestReceived state.", - ) + } val recordId = credentialEvent!!.data.recordId issuer.attemptsTo( Post.to("/issue-credentials/records/$recordId/issue-credential"), @@ -270,33 +207,31 @@ class IssueCredentialsSteps { Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), ) - wait( - { - credentialEvent = ListenToEvents.with(issuer).credentialEvents.lastOrNull { - it.data.thid == issuer.recall("thid") - } - issuer.remember("issuedCredential", credentialEvent!!.data) - credentialEvent != null && + Wait.until( + errorMessage = "Issuer was unable to issue the credential! " + + "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.CREDENTIAL_SENT} state." + ) { + credentialEvent = ListenToEvents.with(issuer).credentialEvents.lastOrNull { + it.data.thid == issuer.recall("thid") + } + issuer.remember("issuedCredential", credentialEvent!!.data) + credentialEvent != null && credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.CREDENTIAL_SENT - }, - "Issuer was unable to issue the credential! " + - "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.CREDENTIAL_SENT} state.", - ) + } } @Then("{actor} receives the issued credential") fun bobHasTheCredentialIssued(holder: Actor) { - wait( - { - credentialEvent = ListenToEvents.with(holder).credentialEvents.lastOrNull { - it.data.thid == holder.recall("thid") - } - credentialEvent != null && + Wait.until( + errorMessage = "Holder was unable to receive the credential from Issuer! " + + "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.CREDENTIAL_RECEIVED} state." + ) { + credentialEvent = ListenToEvents.with(holder).credentialEvents.lastOrNull { + it.data.thid == holder.recall("thid") + } + credentialEvent != null && credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.CREDENTIAL_RECEIVED - }, - "Holder was unable to receive the credential from Issuer! " + - "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.CREDENTIAL_RECEIVED} state.", - ) + } holder.remember("issuedCredential", ListenToEvents.with(holder).credentialEvents.last().data) } diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt index 8ec1a1e808..29999e0ecb 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt @@ -3,6 +3,7 @@ package steps.credentials import interactions.* import io.cucumber.java.en.Then import io.cucumber.java.en.When +import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure import io.iohk.atala.automation.utils.Wait import models.JwtCredential @@ -23,7 +24,7 @@ class RevokeCredentialSteps { issuer.attemptsTo( Get.resource("/credential-status/${statusListId}") ) - val encodedList = SerenityRest.lastResponse().jsonPath().get("credentialSubject.encodedList") + val encodedList = SerenityRest.lastResponse().get("credentialSubject.encodedList") issuer.remember("encodedStatusList", encodedList) issuer.attemptsTo( @@ -49,16 +50,17 @@ class RevokeCredentialSteps { @Then("{actor} should see the credential was revoked") fun credentialShouldBeRevoked(issuer: Actor) { Wait.until( - timeout = 30.seconds, + timeout = 60.seconds, errorMessage = "Encoded Status List didn't change after revoking." ) { - val statusListId = issuer.recall("statusListId") - val encodedList = issuer.recall("statusEncodedList") + val statusListId: String = issuer.recall("statusListId") + val encodedStatusList: String = issuer.recall("encodedStatusList") issuer.attemptsTo( Get.resource("/credential-status/$statusListId") ) - val actualEncodedList = SerenityRest.lastResponse().jsonPath().get("credentialSubject.encodedList") - actualEncodedList != encodedList + val actualEncodedList: String = SerenityRest.lastResponse().jsonPath().get("credentialSubject.encodedList") + println("actual encoded $actualEncodedList | before encoded $encodedStatusList") + actualEncodedList != encodedStatusList } } diff --git a/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt index b95a9f3233..41a9428851 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/DeactivateDidSteps.kt @@ -1,13 +1,12 @@ package steps.did -import common.TestConstants -import common.Utils.wait import interactions.Get import interactions.Post import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.automation.utils.Wait import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus @@ -29,19 +28,19 @@ class DeactivateDidSteps { Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), ) + actor.forget("hasPublishedDid") + val deactivatedDid = actor.forget("shortFormDid") + actor.forget("longFormDid") + actor.remember("deactivatedDid", deactivatedDid) + } @Then("{actor} sees that PRISM DID is successfully deactivated") fun actorSeesThatPrismDidIsSuccessfullyDeactivated(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - SerenityRest.lastResponse().get().didDocumentMetadata.deactivated!! - }, - "ERROR: DID deactivate operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + val deactivatedDid = actor.recall("deactivatedDid") + Wait.until(errorMessage = "ERROR: DID deactivate operation did not succeed on the ledger!") { + actor.attemptsTo(Get.resource("/dids/$deactivatedDid")) + SerenityRest.lastResponse().get().didDocumentMetadata.deactivated!! + } } } diff --git a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt index 90c9d3310e..6c7c2dd2ae 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt @@ -2,49 +2,21 @@ package steps.did import abilities.ListenToEvents import common.TestConstants -import common.Utils.wait import interactions.Get import interactions.Post -import io.cucumber.java.en.Given -import io.cucumber.java.en.Then -import io.cucumber.java.en.When +import io.cucumber.java.en.* import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.automation.utils.Wait import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus import org.apache.http.HttpStatus.SC_CREATED import org.apache.http.HttpStatus.SC_OK import org.hyperledger.identus.client.models.* +import kotlin.time.Duration.Companion.seconds class PublishDidSteps { - - @Given("{actor} have published PRISM DID") - fun actorHavePublishedPrismDid(actor: Actor) { - actor.attemptsTo( - Get.resource("/did-registrar/dids"), - ) - actor.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), - ) - val publishedDids = SerenityRest.lastResponse().get().contents!!.filter { - // TODO: fix openapi spec to have statuses as enum - it.status == "PUBLISHED" - } - val did = publishedDids.firstOrNull { - actor.attemptsTo( - Get.resource("/dids/${it.did}"), - ) - !SerenityRest.lastResponse().get().didDocumentMetadata.deactivated!! - } - if (did == null) { - createsUnpublishedDid(actor) - hePublishesDidToLedger(actor) - } else { - actor.remember("shortFormDid", did.did) - } - } - @Given("{actor} creates unpublished DID") fun createsUnpublishedDid(actor: Actor) { val createDidRequest = CreateManagedDidRequest( @@ -65,27 +37,21 @@ class PublishDidSteps { .with { it.body(createDidRequest) }, - ) - - val managedDid = SerenityRest.lastResponse().get() - actor.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), - Ensure.that(managedDid.longFormDid!!).isNotEmpty(), ) - actor.remember("longFormDid", managedDid.longFormDid) + val managedDid = SerenityRest.lastResponse().get() actor.attemptsTo( + Ensure.that(managedDid.longFormDid!!).isNotEmpty(), Get.resource("/did-registrar/dids/${managedDid.longFormDid}"), - ) - actor.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), ) + val did = SerenityRest.lastResponse().get() - actor.remember( - "shortFormDid", - did.did, - ) + + actor.remember("longFormDid", managedDid.longFormDid) + actor.remember("shortFormDid", did.did) actor.forget("hasPublishedDid") } @@ -128,17 +94,15 @@ class PublishDidSteps { Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), ) - wait( - { - val didEvent = - ListenToEvents.with(actor).didEvents.lastOrNull { - it.data.did == actor.recall("shortFormDid") - } - didEvent != null && didEvent.data.status == "PUBLISHED" - }, - "ERROR: DID was not published to ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + timeout = 30.seconds, + errorMessage = "ERROR: DID was not published to ledger!" + ) { + val didEvent = ListenToEvents.with(actor).didEvents.lastOrNull { + it.data.did == actor.recall("shortFormDid") + } + didEvent != null && didEvent.data.status == "PUBLISHED" + } actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) diff --git a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt index 0f4517d15d..be72209149 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt @@ -1,27 +1,17 @@ package steps.did import common.TestConstants -import common.Utils.wait import interactions.Get import interactions.Post import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.automation.utils.Wait import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus -import org.hyperledger.identus.client.models.ActionType -import org.hyperledger.identus.client.models.DIDOperationResponse -import org.hyperledger.identus.client.models.DIDResolutionResult -import org.hyperledger.identus.client.models.Json -import org.hyperledger.identus.client.models.ManagedDIDKeyTemplate -import org.hyperledger.identus.client.models.Purpose -import org.hyperledger.identus.client.models.RemoveEntryById -import org.hyperledger.identus.client.models.Service -import org.hyperledger.identus.client.models.UpdateManagedDIDRequest -import org.hyperledger.identus.client.models.UpdateManagedDIDRequestAction -import org.hyperledger.identus.client.models.UpdateManagedDIDServiceAction +import org.hyperledger.identus.client.models.* class UpdateDidSteps { @@ -99,94 +89,84 @@ class UpdateDidSteps { @Then("{actor} sees PRISM DID was successfully updated with new keys") fun actorSeesDidSuccessfullyUpdatedWithNewKeys(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! - val verificationMethods = SerenityRest.lastResponse() - .get().didDocument!!.verificationMethod!!.map { it.id } - authUris.any { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_AUTH_KEY.id}" - } && verificationMethods.any { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" - } - }, - "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!" + ) { + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}"), + ) + val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! + val verificationMethods = SerenityRest.lastResponse() + .get().didDocument!!.verificationMethod!!.map { it.id } + authUris.any { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_AUTH_KEY.id}" + } && verificationMethods.any { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" + } + } } @Then("{actor} sees PRISM DID was successfully updated and keys removed") fun actorSeesDidSuccessfullyUpdatedAndKeysRemoved(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! - val verificationMethods = SerenityRest.lastResponse() - .get().didDocument!!.verificationMethod!!.map { it.id } - authUris.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" - } && verificationMethods.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" - } - }, - "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!" + ) { + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}"), + ) + val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! + val verificationMethods = SerenityRest.lastResponse() + .get().didDocument!!.verificationMethod!!.map { it.id } + authUris.none { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" + } && verificationMethods.none { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" + } + } } @Then("{actor} sees PRISM DID was successfully updated with new services") fun actorSeesDidSuccessfullyUpdatedWithNewServices(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - val serviceIds = - SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } - serviceIds.any { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" - } - }, - "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!" + ) { + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}"), + ) + val serviceIds = + SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } + serviceIds.any { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + } + } } @Then("{actor} sees PRISM DID was successfully updated by removing services") fun actorSeesDidSuccessfullyUpdatedByRemovingServices(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - val serviceIds = - SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } - serviceIds.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" - } - }, - "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!" + ) { + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}"), + ) + val serviceIds = + SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } + serviceIds.none { + it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + } + } } @Then("{actor} sees PRISM DID was successfully updated by updating services") fun actorSeesDidSuccessfullyUpdatedByUpdatingServices(actor: Actor) { - wait( - { - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - val service = SerenityRest.lastResponse().get().didDocument!!.service!! - service.any { it.serviceEndpoint.value.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } - }, - "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) + Wait.until( + errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!" + ) { + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}"), + ) + val service = SerenityRest.lastResponse().get().didDocument!!.service!! + service.any { it.serviceEndpoint.value.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } + } } } diff --git a/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt index d0e76cc0da..c4ef7004e7 100644 --- a/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/proofs/AnoncredsPresentProofSteps.kt @@ -1,12 +1,12 @@ package steps.proofs import abilities.ListenToEvents -import common.Utils.wait import interactions.Patch import interactions.Post import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.automation.utils.Wait import models.PresentationEvent import models.PresentationStatusAdapter import net.serenitybdd.rest.SerenityRest @@ -31,15 +31,15 @@ class AnoncredsPresentProofSteps { val anoncredsPresentationRequestV1 = AnoncredPresentationRequestV1( requestedAttributes = mapOf( "sex" to - AnoncredRequestedAttributeV1( - name = "sex", - restrictions = listOf( - mapOf( - ("attr::sex::value" to "M"), - ("cred_def_id" to credentialDefinitionId), + AnoncredRequestedAttributeV1( + name = "sex", + restrictions = listOf( + mapOf( + ("attr::sex::value" to "M"), + ("cred_def_id" to credentialDefinitionId), + ), ), ), - ), ), requestedPredicates = mapOf( "age" to AnoncredRequestedPredicateV1( @@ -77,21 +77,21 @@ class AnoncredsPresentProofSteps { @When("{actor} receives the anoncreds request") fun bobReceivesTheAnoncredsRequest(bob: Actor) { - wait( - { - proofEvent = ListenToEvents.with(bob).presentationEvents.lastOrNull { - it.data.thid == bob.recall("thid") - } - proofEvent != null && - proofEvent!!.data.status == PresentationStatusAdapter.Status.REQUEST_RECEIVED - }, - "ERROR: Bob did not achieve any presentation request!", + Wait.until( + errorMessage = "ERROR: Bob did not achieve any presentation request!" ) + { + proofEvent = ListenToEvents.with(bob).presentationEvents.lastOrNull { + it.data.thid == bob.recall("thid") + } + proofEvent != null && + proofEvent!!.data.status == PresentationStatusAdapter.Status.REQUEST_RECEIVED + } bob.remember("presentationId", proofEvent!!.data.presentationId) } - @When("{actor} accepts the anoncreds presentation request from {actor}") - fun bobAcceptsTheAnoncredsPresentationWithProof(bob: Actor, faber: Actor) { + @When("{actor} accepts the anoncreds presentation request") + fun bobAcceptsTheAnoncredsPresentationWithProof(bob: Actor) { val requestPresentationAction = RequestPresentationAction( anoncredPresentationRequest = AnoncredCredentialProofsV1( @@ -106,8 +106,9 @@ class AnoncredsPresentProofSteps { action = RequestPresentationAction.Action.REQUEST_MINUS_ACCEPT, ) + val presentationId = bob.recall("presentationId") bob.attemptsTo( - Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { + Patch.to("/present-proof/presentations/$presentationId").with { it.body( requestPresentationAction, ) diff --git a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt index 9177f57df2..dc6f8974ee 100644 --- a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt @@ -116,7 +116,7 @@ class PresentProofSteps { @Then("{actor} sees the proof returned verification failed") fun verifierSeesTheProofReturnedVerificationFailed(verifier: Actor) { Wait.until( - timeout = 30.seconds, + timeout = 60.seconds, errorMessage = "Presentation did not achieve PresentationVerificationFailed state!" ) { val proofEvent = ListenToEvents.with(verifier).presentationEvents.lastOrNull { diff --git a/tests/integration-tests/src/test/kotlin/steps/schemas/AnoncredCredentialSchemaSteps.kt b/tests/integration-tests/src/test/kotlin/steps/schemas/AnoncredCredentialSchemaSteps.kt new file mode 100644 index 0000000000..3279777b88 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/steps/schemas/AnoncredCredentialSchemaSteps.kt @@ -0,0 +1,85 @@ +package steps.schemas + +import interactions.Post +import io.cucumber.java.en.Given +import io.cucumber.java.en.When +import io.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.serenity.ensure.Ensure +import models.AnoncredsSchema +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.rest.abilities.CallAnApi +import org.apache.http.HttpStatus.SC_CREATED +import org.hyperledger.identus.client.models.* +import java.util.UUID + +class AnoncredCredentialSchemaSteps { + @Given("{actor} has an anoncred schema definition") + fun issuerHasAnAnoncredSchemaDefinition(issuer: Actor) { + if (issuer.recallAll().containsKey("anoncredsCredentialDefinition")) { + return + } + if (!issuer.recallAll().containsKey("anoncredsSchema")) { + issuerCreatesAnoncredSchema(issuer) + } + issuerCreatesAnoncredCredentialDefinition(issuer) + } + + @When("{actor} creates anoncred schema") + fun issuerCreatesAnoncredSchema(issuer: Actor) { + issuer.attemptsTo( + Post.to("/schema-registry/schemas") + .with { + it.body( + CredentialSchemaInput( + author = issuer.recall("shortFormDid"), + name = UUID.randomUUID().toString(), + description = "Simple student credentials schema", + type = "AnoncredSchemaV1", + schema = AnoncredsSchema( + name = "StudentCredential", + version = "1.0", + issuerId = issuer.recall("shortFormDid"), + attrNames = listOf("name", "age", "sex"), + ), + tags = listOf("school", "students"), + version = "1.0.0", + ), + ) + }, + ) + issuer.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + ) + val schema = SerenityRest.lastResponse().get() + issuer.remember("anoncredsSchema", schema) + } + + @When("{actor} creates anoncred credential definition") + fun issuerCreatesAnoncredCredentialDefinition(issuer: Actor) { + val schemaRegistryUrl = issuer.usingAbilityTo(CallAnApi::class.java).resolve("/schema-registry/schemas") + .replace("localhost", "host.docker.internal") + issuer.attemptsTo( + Post.to("/credential-definition-registry/definitions") + .with { + it.body( + CredentialDefinitionInput( + name = "StudentCredential", + version = "1.0.0", + schemaId = "$schemaRegistryUrl/${issuer.recall("anoncredsSchema").guid}/schema", + description = "Simple student credentials definition", + author = issuer.recall("shortFormDid"), + signatureType = "CL", + tag = "student", + supportRevocation = false, + ), + ) + }, + ) + issuer.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + ) + val credentialDefinition = SerenityRest.lastResponse().get() + issuer.remember("anoncredsCredentialDefinition", credentialDefinition) + } +} diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature deleted file mode 100644 index 309719f74a..0000000000 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature +++ /dev/null @@ -1,36 +0,0 @@ -@RFC0453 @AIP20 @credentials -Feature: Issue Credentials Protocol - - Background: - Given Issuer and Holder have an existing connection - - Scenario: Issuing credential with published PRISM DID - When Issuer creates unpublished DID - And He publishes DID to ledger - And Holder creates unpublished DID - And Issuer offers a credential to Holder with "short" form DID - And Holder receives the credential offer - And Holder accepts credential offer for JWT - And Issuer issues the credential - Then Holder receives the issued credential - - Scenario: Issuing credential with unpublished PRISM DID - When Issuer creates unpublished DID - And Holder creates unpublished DID - And Issuer offers a credential to Holder with "long" form DID - And Holder receives the credential offer - And Holder accepts credential offer for JWT - And Issuer issues the credential - Then Holder receives the issued credential - - Scenario: Issuing anoncred with published PRISM DID - When Issuer creates unpublished DID - And He publishes DID to ledger - And Holder creates unpublished DID - And Issuer creates anoncred schema - And Issuer creates anoncred credential definition - And Issuer offers anoncred to Holder - And Holder receives the credential offer - And Holder accepts credential offer for anoncred - And Issuer issues the credential - Then Holder receives the issued credential diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature index d33c7a021d..c44fa3c948 100644 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature @@ -15,9 +15,8 @@ Feature: Issue Credentials Protocol with published DID Then Holder receives the issued credential Scenario: Issuing anoncred with published PRISM DID - When Issuer creates anoncred schema - And Issuer creates anoncred credential definition - And Issuer offers anoncred to Holder + Given Issuer has an anoncred schema definition + When Issuer offers anoncred to Holder And Holder receives the credential offer And Holder accepts credential offer for anoncred And Issuer issues the credential diff --git a/tests/integration-tests/src/test/resources/features/did/deactivate_did.feature b/tests/integration-tests/src/test/resources/features/did/deactivate_did.feature index bed84078a0..02927820e6 100644 --- a/tests/integration-tests/src/test/resources/features/did/deactivate_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/deactivate_did.feature @@ -1,7 +1,8 @@ -@DLT +@DLT @xubis Feature: Deactivate DID Scenario: Deactivate DID - Given Issuer have published PRISM DID + Given Issuer creates unpublished DID + And Issuer publishes DID to ledger When Issuer deactivates PRISM DID Then He sees that PRISM DID is successfully deactivated diff --git a/tests/integration-tests/src/test/resources/features/did/update_did.feature b/tests/integration-tests/src/test/resources/features/did/update_did.feature index ae474c65fa..ae2496ccb1 100644 --- a/tests/integration-tests/src/test/resources/features/did/update_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/update_did.feature @@ -2,7 +2,7 @@ Feature: Update DID Background: Published DID is created - Given Issuer have published PRISM DID + Given Issuer has a published DID Scenario: Update PRISM DID by adding new services When Issuer updates PRISM DID with new services diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature index cbf44843f6..f439ce3a09 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature @@ -1,3 +1,4 @@ +@proof @jwt Feature: Present Proof Protocol Scenario: Holder presents credential proof to verifier diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature index 9161c46bb4..cee6e19472 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature @@ -1,3 +1,4 @@ +@proof @anoncreds Feature: Present Proof Protocol Scenario: Holder presents anoncreds credential proof to verifier @@ -5,8 +6,7 @@ Scenario: Holder presents anoncreds credential proof to verifier And Verifier and Holder have an existing connection And Issuer has a published DID And Holder has an unpublished DID - And Issuer creates anoncred schema - And Issuer creates anoncred credential definition + And Issuer has an anoncred schema definition And Issuer offers anoncred to Holder And Holder receives the credential offer And Holder accepts credential offer for anoncred @@ -14,5 +14,5 @@ Scenario: Holder presents anoncreds credential proof to verifier And Holder receives the issued credential When Verifier sends a anoncreds request for proof presentation to Holder using credential definition issued by Issuer And Holder receives the anoncreds request - And Holder accepts the anoncreds presentation request from Verifier + And Holder accepts the anoncreds presentation request Then Verifier has the proof verified diff --git a/tests/integration-tests/src/test/resources/features/revocation/jwt.feature b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature similarity index 90% rename from tests/integration-tests/src/test/resources/features/revocation/jwt.feature rename to tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature index 30ec0e5154..a5ae06f110 100644 --- a/tests/integration-tests/src/test/resources/features/revocation/jwt.feature +++ b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature @@ -1,4 +1,4 @@ -@revocation @jwt +@revocation @jwt @xubis Feature: Credential revocation - JWT Background: @@ -18,3 +18,4 @@ Feature: Credential revocation - JWT And Holder receives the request And Holder makes the presentation of the proof to Issuer Then Issuer has the proof verified + And Issuer should see the credential is not revoked