From 27e3a275d1b457b838c7ac2ce55d68a93cb4897e Mon Sep 17 00:00:00 2001 From: Yurii Shynbuiev Date: Thu, 12 Dec 2024 18:46:21 +0700 Subject: [PATCH] test: add e2e test stub for different API variations Signed-off-by: Yurii Shynbuiev --- .../CreateIssueCredentialRecordRequest.kt | 6 ++ tests/integration-tests/build.gradle.kts | 2 +- .../common/CreateCredentialOfferAPIVersion.kt | 64 ++++++++++++++++++ .../test/kotlin/common/CredentialClaims.kt | 19 ++++++ .../src/test/kotlin/common/CredentialType.kt | 19 ++++++ .../steps/credentials/CredentialSteps.kt | 67 +++++++++++++++++++ .../steps/schemas/CredentialSchemasSteps.kt | 2 +- .../jwt/issuance-compatibility.feature | 23 +++++++ .../features/credential/jwt/issuance.feature | 10 +-- .../credential/sdjwt/issuance.feature | 4 +- 10 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 tests/integration-tests/src/test/kotlin/common/CreateCredentialOfferAPIVersion.kt create mode 100644 tests/integration-tests/src/test/kotlin/common/CredentialClaims.kt create mode 100644 tests/integration-tests/src/test/kotlin/common/CredentialType.kt create mode 100644 tests/integration-tests/src/test/resources/features/credential/jwt/issuance-compatibility.feature diff --git a/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/CreateIssueCredentialRecordRequest.kt b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/CreateIssueCredentialRecordRequest.kt index 7518b6a52e..d0d5e44122 100644 --- a/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/CreateIssueCredentialRecordRequest.kt +++ b/cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/CreateIssueCredentialRecordRequest.kt @@ -82,5 +82,11 @@ data class CreateIssueCredentialRecordRequest( @SerializedName("goal") val goal: kotlin.String? = null +// @SerializedName("jwtVcPropertiesV1") +// val jwtVcPropertiesV1: kotlin.collections.List? = null +// @SerializedName("jwtVcPropertiesV1") +// val anoncredsVcPropertiesV1: Option[AnonCredsVCPropertiesV1] = None +// @SerializedName("sdJwtVcPropertiesV1") +// val sdJwtVcPropertiesV1: Option[SDJWTVCPropertiesV1] = None ) diff --git a/tests/integration-tests/build.gradle.kts b/tests/integration-tests/build.gradle.kts index a8b00d3c81..32a67f0073 100644 --- a/tests/integration-tests/build.gradle.kts +++ b/tests/integration-tests/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { testImplementation("io.ktor:ktor-server-netty:2.3.0") testImplementation("io.ktor:ktor-client-apache:2.3.0") // RestAPI client - testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.40.1-c6a3e0c") + testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.40.1-248ba5f") // Test helpers library testImplementation("io.iohk.atala:atala-automation:0.4.0") // Hoplite for configuration diff --git a/tests/integration-tests/src/test/kotlin/common/CreateCredentialOfferAPIVersion.kt b/tests/integration-tests/src/test/kotlin/common/CreateCredentialOfferAPIVersion.kt new file mode 100644 index 0000000000..befcb667f9 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/CreateCredentialOfferAPIVersion.kt @@ -0,0 +1,64 @@ +package common + +import org.hyperledger.identus.client.models.CreateIssueCredentialRecordRequest +import java.util.UUID + +enum class CreateCredentialOfferAPIVersion { + V0 { + override fun buildCredentialOfferRequest( + credentialType: CredentialType, + did: String, + assertionKey: String, + schemaUrl: String?, + claims: Map, + connectionId: UUID, + validityPeriod: Double?, + ): CreateIssueCredentialRecordRequest { + return CreateIssueCredentialRecordRequest( + schemaId = schemaUrl?.let { listOf(it) }, + claims = claims, + issuingDID = did, + issuingKid = assertionKey, + connectionId = connectionId, + validityPeriod = validityPeriod ?: 3600.0, + credentialFormat = credentialType.format, + automaticIssuance = false, + ) + } + }, + + // TODO: it's a copy/paste from the V0, I have to regenerate the Kotlin HTTP client + V1 { + override fun buildCredentialOfferRequest( + credentialType: CredentialType, + did: String, + assertionKey: String, + schemaUrl: String?, + claims: Map, + connectionId: UUID, + validityPeriod: Double?, + ): CreateIssueCredentialRecordRequest { + return CreateIssueCredentialRecordRequest( + schemaId = schemaUrl?.let { listOf(it) }, + claims = claims, + issuingDID = did, + issuingKid = assertionKey, + connectionId = connectionId, + validityPeriod = validityPeriod ?: 3600.0, + credentialFormat = credentialType.format, + automaticIssuance = false, + ) + } + }, + ; + + abstract fun buildCredentialOfferRequest( + credentialType: CredentialType, + did: String, + assertionKey: String, + schemaUrl: String?, + claims: Map, + connectionId: UUID, + validityPeriod: Double? = null, + ): CreateIssueCredentialRecordRequest +} diff --git a/tests/integration-tests/src/test/kotlin/common/CredentialClaims.kt b/tests/integration-tests/src/test/kotlin/common/CredentialClaims.kt new file mode 100644 index 0000000000..a09eb56c33 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/CredentialClaims.kt @@ -0,0 +1,19 @@ +package common + +enum class CredentialClaims { + STUDENT_CLAIMS { + override val claims: Map = linkedMapOf( + "name" to "Name", + "age" to 18, + ) + }, + ID_CLAIMS { + override val claims: Map = linkedMapOf( + "firstName" to "First Name", + "lastName" to "Last Name", + ) + }, + ; + + abstract val claims: Map +} diff --git a/tests/integration-tests/src/test/kotlin/common/CredentialType.kt b/tests/integration-tests/src/test/kotlin/common/CredentialType.kt new file mode 100644 index 0000000000..88cbe7ca1e --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/CredentialType.kt @@ -0,0 +1,19 @@ +package common + +enum class CredentialType { + JWT_VCDM_1_1 { + override val format: String = "JWT" + }, + JWT_VCDM_2_0 { + override val format: String = "JWT" + }, + ANONCREDS_V1 { + override val format: String = "AnonCreds" + }, + SD_JWT_VCDM_1_1 { + override val format: String = "SD_JWT" + }, + ; + + abstract val format: String +} diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/CredentialSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/CredentialSteps.kt index d3aac42ea4..1ad3fa1c07 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/CredentialSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/CredentialSteps.kt @@ -1,11 +1,15 @@ package steps.credentials import abilities.ListenToEvents +import common.* import interactions.Post +import interactions.body 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.serenity.interactions.PollingWait +import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.* import org.hamcrest.CoreMatchers.equalTo @@ -42,6 +46,69 @@ class CredentialSteps { ) } + @When("{actor} prepares the credential in '{}' format using the '{}' API") + fun issuerPreparesTheCredentialInFormat(issuer: Actor, credentialType: CredentialType, apiVersion: CreateCredentialOfferAPIVersion) { + issuer.remember("currentCredentialType", credentialType) + issuer.remember("currentAPI", apiVersion) + } + + @When("{actor} prepares the '{}' to issue the credential") + fun issuerPreparesTheSchemaToIssueTheCredential(issuer: Actor, schema: CredentialSchema) { + issuer.remember("currentSchema", schema) + } + + @When("{actor} prepares to use a '{}' form of DID with key id '{}'") + fun issuerPreparesTheDIDWithTheKeyId(issuer: Actor, didForm: String, assertionKey: String) { + val did: String = if (didForm == "short") { + issuer.recall("shortFormDid") + } else { + issuer.recall("longFormDid") + } + issuer.remember("currentDID", did) + issuer.remember("currentAssertionKey", assertionKey) + } + + @When("{actor} prepares the claims '{}' for the credential") + fun issuerPreparesTheClaims(issuer: Actor, credentialClaims: CredentialClaims) { + issuer.remember("currentClaims", credentialClaims.claims) + } + + @When("{actor} sends the prepared credential offer to {actor}") + fun issuerSendsTheCredentialOfferToHolder(issuer: Actor, holder: Actor) { + val api = issuer.recall("currentAPI") + val credentialType = issuer.recall("currentCredentialType") + val did = issuer.recall("currentDID") + val assertionKey = issuer.recall("currentAssertionKey") + val schema = issuer.recall("currentSchema") + val schemaGuid = issuer.recall(schema.name) + val claims = issuer.recall>("currentClaims") + + val connectionId = issuer.recall("connection-with-${holder.name}").connectionId + + val schemaUrl: String? = schemaGuid?.let { + "${issuer.recall("baseUrl")}/schema-registry/schemas/$it" + } + + val credentialOfferRequest = api.buildCredentialOfferRequest(credentialType, did, assertionKey, schemaUrl!!, claims, connectionId) + + issuer.attemptsTo( + Post.to("/issue-credentials/credential-offers").body(credentialOfferRequest), + ) + + saveCredentialOffer(issuer, holder) + } + + private fun saveCredentialOffer(issuer: Actor, holder: Actor) { + val credentialRecord = SerenityRest.lastResponse().get() + + issuer.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + ) + + issuer.remember("thid", credentialRecord.thid) + holder.remember("thid", credentialRecord.thid) + } + @When("{actor} issues the credential") fun issuerIssuesTheCredential(issuer: Actor) { issuerTriesToIssueTheCredential(issuer) diff --git a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt index 37511cd35f..8f4474a6b2 100644 --- a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt @@ -16,7 +16,7 @@ import java.util.UUID class CredentialSchemasSteps { - @Given("{actor} has published '{}' schema") + @Given("{actor} has a published '{}' schema") fun agentHasAPublishedSchema(agent: Actor, schema: CredentialSchema) { if (agent.recallAll().containsKey(schema.name)) { return diff --git a/tests/integration-tests/src/test/resources/features/credential/jwt/issuance-compatibility.feature b/tests/integration-tests/src/test/resources/features/credential/jwt/issuance-compatibility.feature new file mode 100644 index 0000000000..4953ab041f --- /dev/null +++ b/tests/integration-tests/src/test/resources/features/credential/jwt/issuance-compatibility.feature @@ -0,0 +1,23 @@ +@jwt @issuance @compatibility +Feature: Issue JWT credential REST API compatibility + + Background: + Given Issuer and Holder have an existing connection + And Issuer has a published DID for 'JWT' + And Issuer has a published 'STUDENT_SCHEMA' schema + And Holder has an unpublished DID for 'JWT' + + Scenario Outline: Issuing jwt credential using different API version + When Issuer prepares the credential in 'JWT_VCDM_1_1' format using the '' API + And Issuer prepares to use a 'short' form of DID with key id 'assertion-1' + And Issuer prepares the 'STUDENT_SCHEMA' to issue the credential + And Issuer prepares the claims '' for the credential + And Issuer sends the prepared credential offer to Holder + And Holder receives the credential offer + And Holder accepts jwt credential offer using 'auth-1' key id + And Issuer issues the credential + Then Holder receives the issued credential + Examples: + | createCredentialOfferApiVersion | claims | + | V0 | STUDENT_CLAIMS | + diff --git a/tests/integration-tests/src/test/resources/features/credential/jwt/issuance.feature b/tests/integration-tests/src/test/resources/features/credential/jwt/issuance.feature index a8f9082b67..21e117342b 100644 --- a/tests/integration-tests/src/test/resources/features/credential/jwt/issuance.feature +++ b/tests/integration-tests/src/test/resources/features/credential/jwt/issuance.feature @@ -5,7 +5,7 @@ Feature: Issue JWT credential Given Issuer and Holder have an existing connection And Holder creates unpublished DID for 'JWT' When Issuer prepares a custom PRISM DID - And Issuer has published 'STUDENT_SCHEMA' schema + And Issuer has a published 'STUDENT_SCHEMA' schema And Issuer adds a '' key for 'assertionMethod' purpose with '' name to the custom PRISM DID And Issuer creates the custom PRISM DID And Issuer publishes DID to ledger @@ -28,7 +28,7 @@ Feature: Issue JWT credential Scenario: Issuing jwt credential with published PRISM DID and student schema Given Issuer and Holder have an existing connection And Issuer has a published DID for 'JWT' - And Issuer has published 'STUDENT_SCHEMA' schema + And Issuer has a published 'STUDENT_SCHEMA' schema And Holder has an unpublished DID for 'JWT' When Issuer offers a jwt credential to Holder with 'short' form using 'STUDENT_SCHEMA' schema And Holder receives the credential offer @@ -39,7 +39,7 @@ Feature: Issue JWT credential Scenario: Issuing jwt credential with wrong claim structure for schema Given Issuer and Holder have an existing connection And Issuer has a published DID for 'JWT' - And Issuer has published 'STUDENT_SCHEMA' schema + And Issuer has a published 'STUDENT_SCHEMA' schema And Holder has an unpublished DID for 'JWT' When Issuer offers a jwt credential to Holder with 'short' form DID with wrong claims structure using 'STUDENT_SCHEMA' schema Then Issuer should see that credential issuance has failed @@ -47,7 +47,7 @@ Feature: Issue JWT credential Scenario: Issuing jwt credential with unpublished PRISM DID Given Issuer and Holder have an existing connection And Issuer has an unpublished DID for 'JWT' - And Issuer has published 'STUDENT_SCHEMA' schema + And Issuer has a published 'STUDENT_SCHEMA' schema And Holder has an unpublished DID for 'JWT' And Issuer offers a jwt credential to Holder with 'long' form DID And Holder receives the credential offer @@ -57,7 +57,7 @@ Feature: Issue JWT credential Scenario: Connectionless issuance of JWT credential using OOB invitation Given Issuer has a published DID for 'JWT' - And Issuer has published 'STUDENT_SCHEMA' schema + And Issuer has a published 'STUDENT_SCHEMA' schema And Holder has an unpublished DID for 'JWT' When Issuer creates a 'JWT' credential offer invitation with 'short' form DID and STUDENT_SCHEMA schema And Holder accepts the credential offer invitation from Issuer diff --git a/tests/integration-tests/src/test/resources/features/credential/sdjwt/issuance.feature b/tests/integration-tests/src/test/resources/features/credential/sdjwt/issuance.feature index 9a0d982a20..d981fa9fc8 100644 --- a/tests/integration-tests/src/test/resources/features/credential/sdjwt/issuance.feature +++ b/tests/integration-tests/src/test/resources/features/credential/sdjwt/issuance.feature @@ -23,7 +23,7 @@ Feature: Issue SD-JWT credential Scenario: Issuing sd-jwt credential with holder binding Given Issuer and Holder have an existing connection And Issuer has a published DID for 'SD_JWT' - And Issuer has published 'ID_SCHEMA' schema + And Issuer has a published 'ID_SCHEMA' schema And Holder has an unpublished DID for 'SD_JWT' When Issuer offers a sd-jwt credential to Holder And Holder receives the credential offer @@ -34,7 +34,7 @@ Feature: Issue SD-JWT credential Scenario: Connectionless issuance of sd-jwt credential with holder binding And Issuer has a published DID for 'SD_JWT' - And Issuer has published 'ID_SCHEMA' schema + And Issuer has a published 'ID_SCHEMA' schema And Holder has an unpublished DID for 'SD_JWT' When Issuer creates a 'SDJWT' credential offer invitation with 'short' form DID and ID_SCHEMA schema And Holder accepts the credential offer invitation from Issuer