diff --git a/infrastructure/shared/docker-compose-demo.yml b/infrastructure/shared/docker-compose-demo.yml index 2021606da1..14a42d9b33 100644 --- a/infrastructure/shared/docker-compose-demo.yml +++ b/infrastructure/shared/docker-compose-demo.yml @@ -23,6 +23,8 @@ services: image: ghcr.io/input-output-hk/prism-node:${PRISM_NODE_VERSION} environment: NODE_PSQL_HOST: db:5432 + NODE_REFRESH_AND_SUBMIT_PERIOD: 1s + NODE_MOVE_SCHEDULED_TO_PENDING_PERIOD: 1s depends_on: db: condition: service_healthy diff --git a/tests/e2e-tests/build.gradle.kts b/tests/e2e-tests/build.gradle.kts deleted file mode 100644 index 4e9d088ca1..0000000000 --- a/tests/e2e-tests/build.gradle.kts +++ /dev/null @@ -1,55 +0,0 @@ -plugins { - id("org.jetbrains.kotlin.jvm") version "1.9.0" - idea - jacoco - id("net.serenity-bdd.serenity-gradle-plugin") version "4.0.1" - kotlin("plugin.serialization") version "1.9.0" -} - -repositories { - mavenCentral() -} - -dependencies { - // Logging - implementation("org.slf4j:slf4j-log4j12:2.0.5") - // Beautify async waits - implementation("org.awaitility:awaitility-kotlin:4.2.0") - // Test engines and reports - testImplementation("junit:junit:4.13.2") - implementation("net.serenity-bdd:serenity-core:4.0.1") - implementation("net.serenity-bdd:serenity-cucumber:4.0.1") - implementation("net.serenity-bdd:serenity-screenplay-rest:4.0.1") - testImplementation("net.serenity-bdd:serenity-ensure:4.0.1") - // Beautify exceptions handling assertions - testImplementation("org.assertj:assertj-core:3.23.1") - // Navigate through Json with xpath - testImplementation("com.jayway.jsonpath:json-path:2.7.0") - // HTTP listener - implementation("io.ktor:ktor-server-netty:2.3.0") - implementation("io.ktor:ktor-client-apache:2.3.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") -} - -buildscript { - dependencies { - classpath("net.serenity-bdd:serenity-single-page-report:4.0.1") - classpath("net.serenity-bdd:serenity-json-summary-report:4.0.1") - } -} - -/** - * Add HTML one-pager and JSON summary report to be produced - */ -serenity { - reports = listOf("single-page-html", "json-summary") -} - -tasks.test { - testLogging.showStandardStreams = true - systemProperty("cucumber.filter.tags", System.getProperty("cucumber.filter.tags")) -} - -kotlin { - jvmToolchain(19) -} diff --git a/tests/e2e-tests/settings.gradle.kts b/tests/e2e-tests/settings.gradle.kts deleted file mode 100644 index 40b97a0ff6..0000000000 --- a/tests/e2e-tests/settings.gradle.kts +++ /dev/null @@ -1,2 +0,0 @@ - -rootProject.name = "e2e-tests" diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt b/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt deleted file mode 100644 index 37096a7609..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Connection.kt +++ /dev/null @@ -1,27 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class Connection( - var connectionId: String = "", - var thid: String = "", - var createdAt: String = "", - var updatedAt: String = "", - var invitation: Invitation = Invitation(), - var kind: String = "", - var self: String = "", - var state: String = "", - var label: String = "", - var myDid: String = "", - var theirDid: String = "", - var role: String = "", - var metaRetries: Int = 0, -): JsonEncoded - -object ConnectionState { - const val INVITATION_GENERATED = "InvitationGenerated" - const val CONNECTION_REQUEST_PENDING = "ConnectionRequestPending" - const val CONNECTION_RESPONSE_SENT = "ConnectionResponseSent" - const val CONNECTION_RESPONSE_RECEIVED = "ConnectionResponseReceived" -} diff --git a/tests/e2e-tests/src/main/kotlin/api_models/CreatePrismDidRequest.kt b/tests/e2e-tests/src/main/kotlin/api_models/CreatePrismDidRequest.kt deleted file mode 100644 index 4c90ac84c4..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/CreatePrismDidRequest.kt +++ /dev/null @@ -1,5 +0,0 @@ -package api_models - -data class CreatePrismDidRequest( - val documentTemplate: DocumentTemplate, -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/CredentialSchema.kt b/tests/e2e-tests/src/main/kotlin/api_models/CredentialSchema.kt deleted file mode 100644 index be0c860cc1..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/CredentialSchema.kt +++ /dev/null @@ -1,19 +0,0 @@ -package api_models - -import com.fasterxml.jackson.databind.JsonNode - -data class CredentialSchema( - var name: String? = null, - var version: String? = null, - var tags: List? = listOf(""), - var description: String? = null, - var type: String? = null, - var author: String? = null, - var authored: String? = null, - var schema: JsonNode? = null, - var guid: String? = null, - var longId: String? = null, - var id: String? = null, - var kind: String? = null, - var self: String? = null, -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt b/tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt deleted file mode 100644 index cedf10631c..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/DidResolutionResult.kt +++ /dev/null @@ -1,64 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class DidResolutionResult( - var `@context`: String? = null, - var didDocument: DidDocument? = null, - var didDocumentMetadata: DidDocumentMetadata? = null, - var didResolutionMetadata: DidResolutionMetadata? = null, -): JsonEncoded - -@Serializable -data class DidDocument( - var `@context`: List? = null, - var assertionMethod: List? = null, - var authentication: List? = null, - var capabilityInvocation: List? = null, - var capabilityDelegation: List? = null, - var controller: String? = null, - var id: String? = null, - var keyAgreement: List? = null, - var service: List? = null, - var verificationMethod: List? = null, -): JsonEncoded - -@Serializable -data class VerificationMethod( - var controller: String? = null, - var id: String? = null, - var publicKeyJwk: PublicKeyJwk? = null, - var type: String? = null, -): JsonEncoded - -typealias VerificationMethodRef = String - -@Serializable -data class PublicKeyJwk( - var crv: String? = null, - var kty: String? = null, - var x: String? = null, - var y: String? = null, -): JsonEncoded - -@Serializable -data class DidDocumentMetadata( - var canonicalId: String? = null, - var versionId: String? = null, - var deactivated: Boolean? = null, - var created: String? = null, - var updated: String? = null, -): JsonEncoded - -@Serializable -data class DidDocumentService( - var id: String? = null, - var serviceEndpoint: List? = null, - var type: String? = null, -): JsonEncoded - -@Serializable -data class DidResolutionMetadata( - var contentType: String? = null, -): JsonEncoded diff --git a/tests/e2e-tests/src/main/kotlin/api_models/DocumentTemplate.kt b/tests/e2e-tests/src/main/kotlin/api_models/DocumentTemplate.kt deleted file mode 100644 index fb52838955..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/DocumentTemplate.kt +++ /dev/null @@ -1,6 +0,0 @@ -package api_models - -data class DocumentTemplate( - val publicKeys: List, - val services: List, -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Entity.kt b/tests/e2e-tests/src/main/kotlin/api_models/Entity.kt deleted file mode 100644 index 6035d98f50..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Entity.kt +++ /dev/null @@ -1,16 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class CreateEntityRequest( - val walletId: String, - val name: String, - val id: String, -): JsonEncoded - -@Serializable -data class AddApiKeyRequest( - val entityId: String, - val apiKey: String, -): JsonEncoded diff --git a/tests/e2e-tests/src/main/kotlin/api_models/EventRegistration.kt b/tests/e2e-tests/src/main/kotlin/api_models/EventRegistration.kt deleted file mode 100644 index 6c152b45bd..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/EventRegistration.kt +++ /dev/null @@ -1,8 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class RegisterWebhookRequest( - val url: String, -) :JsonEncoded diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Events.kt b/tests/e2e-tests/src/main/kotlin/api_models/Events.kt deleted file mode 100644 index 817274ffe4..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Events.kt +++ /dev/null @@ -1,49 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonElement - -@Serializable -data class Event( - var type: String, - var id: String, - var ts: String, - var data: JsonElement, - var walletId: String, -) : JsonEncoded - -@Serializable -data class ConnectionEvent( - var type: String, - var id: String, - var ts: String, - var data: Connection, - var walletId: String, -) : JsonEncoded - -@Serializable -data class CredentialEvent( - var type: String, - var id: String, - var ts: String, - var data: Credential, - var walletId: String, -) : JsonEncoded - -@Serializable -data class PresentationEvent( - var type: String, - var id: String, - var ts: String, - var data: PresentationProof, - var walletId: String, -) : JsonEncoded - -@Serializable -data class DidEvent( - var type: String, - var id: String, - var ts: String, - var data: ManagedDid, - var walletId: String, -) : JsonEncoded diff --git a/tests/e2e-tests/src/main/kotlin/api_models/HealthInfo.kt b/tests/e2e-tests/src/main/kotlin/api_models/HealthInfo.kt deleted file mode 100644 index 896c228f42..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/HealthInfo.kt +++ /dev/null @@ -1,4 +0,0 @@ -package api_models -data class HealthInfo( - var version: String = "", -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Invitation.kt b/tests/e2e-tests/src/main/kotlin/api_models/Invitation.kt deleted file mode 100644 index 93cb6f4fe8..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Invitation.kt +++ /dev/null @@ -1,11 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class Invitation( - var id: String = "", - var from: String = "", - var invitationUrl: String = "", - var type: String = "", -): JsonEncoded diff --git a/tests/e2e-tests/src/main/kotlin/api_models/JsonEncoded.kt b/tests/e2e-tests/src/main/kotlin/api_models/JsonEncoded.kt deleted file mode 100644 index 560d6132f1..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/JsonEncoded.kt +++ /dev/null @@ -1,12 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json - -@Serializable -sealed interface JsonEncoded { - fun toJsonString(): String { - return Json.encodeToString(this) - } -} diff --git a/tests/e2e-tests/src/main/kotlin/api_models/ManagedDid.kt b/tests/e2e-tests/src/main/kotlin/api_models/ManagedDid.kt deleted file mode 100644 index e5063ffc30..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/ManagedDid.kt +++ /dev/null @@ -1,15 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class ManagedDid( - var did: String = "", - var longFormDid: String = "", - var status: String = "", -): JsonEncoded - -object ManagedDidStatuses { - val PUBLISHED = "PUBLISHED" - val CREATED = "CREATED" -} diff --git a/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt b/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt deleted file mode 100644 index 2f617a3571..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/PresentationProof.kt +++ /dev/null @@ -1,21 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class PresentationProof( - var presentationId: String? = null, - var thid: String? = null, - var status: String? = null, - var connectionId: String? = null, - var proofs: List? = null, - var data: List? = null, - var role: String? = null, - var metaRetries: Int = 0, -): JsonEncoded - -object PresentationProofStatus { - const val REQUEST_RECEIVED = "RequestReceived" - const val REQUEST_REJECTED = "RequestRejected" - const val PRESENTATION_VERIFIED = "PresentationVerified" -} diff --git a/tests/e2e-tests/src/main/kotlin/api_models/PublicKey.kt b/tests/e2e-tests/src/main/kotlin/api_models/PublicKey.kt deleted file mode 100644 index 9e53427ea4..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/PublicKey.kt +++ /dev/null @@ -1,16 +0,0 @@ -package api_models - -import com.fasterxml.jackson.annotation.JsonValue - -data class PublicKey( - val id: String, - val purpose: Purpose, -) - -enum class Purpose(@JsonValue val value: String) { - AUTHENTICATION("authentication"), - ASSERTION_METHOD("assertionMethod"), - KEY_AGREEMENT("keyAgreement"), - CAPABILITY_INVOCATION("capabilityInvocation"), - CAPABILITY_DELEGATION("capabilityDelegation"), -} diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Service.kt b/tests/e2e-tests/src/main/kotlin/api_models/Service.kt deleted file mode 100644 index 1fb68ee4f4..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Service.kt +++ /dev/null @@ -1,7 +0,0 @@ -package api_models - -data class Service( - var id: String = "", - var serviceEndpoint: List = listOf(""), - var type: String = "", -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/UpdatePrismDidRequest.kt b/tests/e2e-tests/src/main/kotlin/api_models/UpdatePrismDidRequest.kt deleted file mode 100644 index d9681335e0..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/UpdatePrismDidRequest.kt +++ /dev/null @@ -1,14 +0,0 @@ -package api_models - -data class UpdatePrismDidRequest( - val actions: List, -) - -data class UpdatePrismDidAction( - val actionType: String? = null, - val addKey: PublicKey? = null, - val removeKey: PublicKey? = null, - val addService: Service? = null, - val removeService: Service? = null, - val updateService: Service? = null, -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/VerificationPolicy.kt b/tests/e2e-tests/src/main/kotlin/api_models/VerificationPolicy.kt deleted file mode 100644 index c3eb0caf21..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/VerificationPolicy.kt +++ /dev/null @@ -1,24 +0,0 @@ -package api_models - -data class VerificationPolicy( - var id: String? = null, - var nonce: String? = null, - var name: String? = null, - var description: String? = null, - var constraints: List? = null, - var createdAt: String? = null, - var updatedAt: String? = null, - var kind: String? = null, - var self: String? = null, -) - -data class VerificationPolicyInput( - var name: String? = null, - var description: String? = null, - var constraints: List? = null, -) - -data class Constraint( - var schemaId: String? = null, - var trustedIssuers: List? = null, -) diff --git a/tests/e2e-tests/src/main/kotlin/api_models/Wallet.kt b/tests/e2e-tests/src/main/kotlin/api_models/Wallet.kt deleted file mode 100644 index 4bb7283bc8..0000000000 --- a/tests/e2e-tests/src/main/kotlin/api_models/Wallet.kt +++ /dev/null @@ -1,10 +0,0 @@ -package api_models - -import kotlinx.serialization.Serializable - -@Serializable -data class CreateWalletRequest( - val name: String, - val seed: String, - val id: String, -): JsonEncoded diff --git a/tests/e2e-tests/src/test/kotlin/common/CredentialSchemas.kt b/tests/e2e-tests/src/test/kotlin/common/CredentialSchemas.kt deleted file mode 100644 index 70338cc29f..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/CredentialSchemas.kt +++ /dev/null @@ -1,51 +0,0 @@ -package common - -import api_models.CredentialSchema -import com.fasterxml.jackson.databind.ObjectMapper -import java.util.* - -object CredentialSchemas { - - val CREDENTIAL_SCHEMA_TYPE = "https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json" - - val SCHEMA_TYPE = "https://json-schema.org/draft/2020-12/schema" - - val JSON_SCHEMA = """ - { - "${"$"}id": "https://example.com/student-schema-1.0", - "${"$"}schema": "$SCHEMA_TYPE", - "description": "Student schema", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "age": { - "type": "integer" - } - } - } - """.trimIndent() - - fun generate_with_name_suffix_and_author(suffix: String, author: String): CredentialSchema { - return CredentialSchema( - author = author, - name = "${UUID.randomUUID()} $suffix", - description = "Simple student credentials schema", - type = CREDENTIAL_SCHEMA_TYPE, - schema = ObjectMapper().readTree(JSON_SCHEMA), - tags = listOf("school", "students"), - version = "1.0.0", - ) - } - - val STUDENT_SCHEMA = CredentialSchema( - author = "did:prism:agent", - name = UUID.randomUUID().toString(), - description = "Simple student credentials schema", - type = CREDENTIAL_SCHEMA_TYPE, - schema = ObjectMapper().readTree(JSON_SCHEMA), - tags = listOf("school", "students"), - version = "1.0.0", - ) -} diff --git a/tests/e2e-tests/src/test/kotlin/common/Ensure.kt b/tests/e2e-tests/src/test/kotlin/common/Ensure.kt deleted file mode 100644 index 491437276d..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/Ensure.kt +++ /dev/null @@ -1,52 +0,0 @@ -package common - -import net.serenitybdd.screenplay.Question -import org.openqa.selenium.By -import java.time.LocalDate -import java.time.LocalTime -import net.serenitybdd.screenplay.ensure.enableSoftAssertions as EnableSoftAssertions -import net.serenitybdd.screenplay.ensure.reportSoftAssertions as ReportSoftAssertions -import net.serenitybdd.screenplay.ensure.that as That -import net.serenitybdd.screenplay.ensure.thatAmongst as ThatAmongst -import net.serenitybdd.screenplay.ensure.thatTheCurrentPage as ThatTheCurrentPage -import net.serenitybdd.screenplay.ensure.thatTheListOf as ThatTheListOf -import net.serenitybdd.screenplay.targets.Target as SerenityTarget - -object Ensure { - fun that(value: String?) = That(value) - fun that(value: LocalDate) = That(value) - fun that(value: LocalTime) = That(value) - fun that(value: Boolean) = That(value) - fun that(value: Float) = That(value) - fun that(value: Double) = That(value) - - fun that(value: Comparable) = That(value) - fun that(value: Collection) = That(value) - - fun that(question: Question, predicate: (actual: A) -> Boolean) = That(question, predicate) - fun that(description: String, question: Question, predicate: (actual: A) -> Boolean) = - That(description, question, predicate) - - fun > that(description: String, question: Question) = That(description, question) - fun > that(question: Question) = That(question) - - fun that(description: String, question: Question>) = That(description, question) - fun that(question: Question>) = That(question) - - fun thatTheListOf(description: String, question: Question>) = ThatTheListOf(description, question) - fun thatTheListOf(question: Question>) = ThatTheListOf(question) - - fun thatTheCurrentPage() = ThatTheCurrentPage() - fun that(value: SerenityTarget) = That(value) - fun that(value: By) = net.serenitybdd.screenplay.ensure.that(value) - - // Collection matchers - fun thatTheListOf(value: SerenityTarget) = ThatTheListOf(value) - fun thatTheListOf(value: By) = ThatTheListOf(value) - - fun thatAmongst(value: SerenityTarget) = ThatAmongst(value) - fun thatAmongst(value: By) = ThatAmongst(value) - - fun enableSoftAssertions() = EnableSoftAssertions() - fun reportSoftAssertions() = ReportSoftAssertions() -} diff --git a/tests/e2e-tests/src/test/kotlin/common/Environments.kt b/tests/e2e-tests/src/test/kotlin/common/Environments.kt deleted file mode 100644 index eebbe6db36..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/Environments.kt +++ /dev/null @@ -1,24 +0,0 @@ -package common - -object Environments { - val AGENT_AUTH_REQUIRED: Boolean = (System.getenv("AGENT_AUTH_REQUIRED") ?: "true").toBoolean() - val AGENT_AUTH_HEADER = System.getenv("AGENT_AUTH_HEADER") ?: "apikey" - val ACME_AUTH_KEY = System.getenv("ACME_AUTH_KEY") ?: "SECURE_ACME_AUTH_KEY_GREATER_16_SYMBOLS" - val ACME_AGENT_URL = System.getenv("ACME_AGENT_URL") ?: "http://localhost:8080/prism-agent" - val ACME_AGENT_WEBHOOK_HOST = System.getenv("ACME_AGENT_WEBHOOK_HOST") ?: "host.docker.internal" - val ACME_AGENT_WEBHOOK_PORT = (System.getenv("ACME_AGENT_WEBHOOK_PORT") ?: "9955").toInt() - val ACME_AGENT_WEBHOOK_URL = "http://$ACME_AGENT_WEBHOOK_HOST:$ACME_AGENT_WEBHOOK_PORT" - val BOB_AGENT_URL = System.getenv("BOB_AGENT_URL") ?: "http://localhost:8090/prism-agent" - val BOB_AUTH_KEY = System.getenv("BOB_AUTH_KEY") ?: "default" - val BOB_AGENT_WEBHOOK_HOST = System.getenv("BOB_AGENT_WEBHOOK_HOST") ?: "host.docker.internal" - val BOB_AGENT_WEBHOOK_PORT = (System.getenv("BOB_AGENT_WEBHOOK_PORT") ?: "9956").toInt() - val BOB_AGENT_WEBHOOK_URL = "http://$BOB_AGENT_WEBHOOK_HOST:$BOB_AGENT_WEBHOOK_PORT" - val FABER_AGENT_URL = System.getenv("FABER_AGENT_URL") ?: "http://localhost:8080/prism-agent" - val FABER_AUTH_KEY = System.getenv("FABER_AUTH_KEY") ?: "SECURE_FABER_AUTH_KEY_GREATER_16_SYMBOLS" - val FABER_AGENT_WEBHOOK_HOST = System.getenv("FABER_AGENT_WEBHOOK_HOST") ?: "host.docker.internal" - val FABER_AGENT_WEBHOOK_PORT = (System.getenv("FABER_AGENT_WEBHOOK_PORT") ?: "9957").toInt() - val FABER_AGENT_WEBHOOK_URL = "http://$FABER_AGENT_WEBHOOK_HOST:$FABER_AGENT_WEBHOOK_PORT" - val ADMIN_AGENT_URL = ACME_AGENT_URL - val ADMIN_AUTH_HEADER = System.getenv("ADMIN_AUTH_HEADER") ?: "x-admin-api-key" - val ADMIN_AUTH_TOKEN = System.getenv("ADMIN_AUTH_TOKEN") ?: "admin" -} diff --git a/tests/e2e-tests/src/test/kotlin/common/TestConstants.kt b/tests/e2e-tests/src/test/kotlin/common/TestConstants.kt deleted file mode 100644 index 21bf3c67e9..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/TestConstants.kt +++ /dev/null @@ -1,43 +0,0 @@ -package common - -import api_models.PublicKey -import api_models.Purpose -import api_models.Service -import java.time.Duration -import java.util.* - -object TestConstants { - val VERIFICATION_POLICIES = VerificationPolicies - val CREDENTIAL_SCHEMAS = CredentialSchemas - val RANDOM_CONSTAND_UUID = UUID.randomUUID().toString() - val DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN = Duration.ofSeconds(60L) - val PRISM_DID_AUTH_KEY = PublicKey("auth-1", Purpose.AUTHENTICATION) - val PRISM_DID_ASSERTION_KEY = PublicKey("assertion-1", Purpose.ASSERTION_METHOD) - val PRISM_DID_UPDATE_NEW_AUTH_KEY = PublicKey("auth-2", Purpose.AUTHENTICATION) - val PRISM_DID_SERVICE = Service( - "https://foo.bar.com", - listOf("https://foo.bar.com/"), - "LinkedDomains", - ) - val PRISM_DID_SERVICE_FOR_UPDATE = Service( - "https://update.com", - listOf("https://update.com/"), - "LinkedDomains", - ) - val PRISM_DID_SERVICE_TO_REMOVE = Service( - "https://remove.com", - listOf("https://remove.com/"), - "LinkedDomains", - ) - val PRISM_DID_UPDATE_NEW_SERVICE_URL = "https://bar.foo.com/" - val PRISM_DID_UPDATE_NEW_SERVICE = Service( - "https://new.service.com", - listOf("https://new.service.com/"), - "LinkedDomains", - ) - val EVENT_TYPE_CONNECTION_UPDATED = "ConnectionUpdated" - val EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED = "IssueCredentialRecordUpdated" - val EVENT_TYPE_PRESENTATION_UPDATED = "PresentationUpdated" - val EVENT_TYPE_DID_STATUS_UPDATED = "DIDStatusUpdated" - val WRONG_SEED = "wrong seed" -} diff --git a/tests/e2e-tests/src/test/kotlin/common/Utils.kt b/tests/e2e-tests/src/test/kotlin/common/Utils.kt deleted file mode 100644 index b4d3fa53fd..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/Utils.kt +++ /dev/null @@ -1,52 +0,0 @@ -package common - -import com.fasterxml.jackson.databind.ObjectMapper -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import net.serenitybdd.rest.SerenityRest -import org.awaitility.Awaitility -import org.awaitility.core.ConditionTimeoutException -import org.awaitility.kotlin.withPollInterval -import org.awaitility.pollinterval.FixedPollInterval -import java.time.Duration -import kotlin.reflect.KClass - -object Utils { - - fun lastResponseObject(path: String, clazz: KClass): T { - return SerenityRest.lastResponse().jsonPath().getObject(path, clazz.java) - } - - fun lastResponseList(path: String, clazz: KClass): List { - return SerenityRest.lastResponse().jsonPath().getList(path, clazz.java) - } - - fun lastResponseMap(path: String, keyType: KClass, valueType: KClass): Map { - return SerenityRest.lastResponse().jsonPath().getMap(path, keyType.java, valueType.java) - } - - fun toJsonPath(any: Any): DocumentContext { - val json = ObjectMapper().writeValueAsString(any) - return JsonPath.parse(json) - } - - fun wait( - blockToWait: () -> Boolean, - errorMessage: String, - poolInterval: FixedPollInterval = FixedPollInterval(Duration.ofMillis(500L)), - timeout: Duration = Duration.ofSeconds(120L), - ) { - try { - Awaitility.await().withPollInterval(poolInterval) - .pollInSameThread() - .atMost(timeout) - .until { - blockToWait() - } - } catch (err: ConditionTimeoutException) { - throw ConditionTimeoutException( - errorMessage, - ) - } - } -} diff --git a/tests/e2e-tests/src/test/kotlin/common/VerificationPolicies.kt b/tests/e2e-tests/src/test/kotlin/common/VerificationPolicies.kt deleted file mode 100644 index a79fff24ff..0000000000 --- a/tests/e2e-tests/src/test/kotlin/common/VerificationPolicies.kt +++ /dev/null @@ -1,25 +0,0 @@ -package common - -import api_models.Constraint -import api_models.VerificationPolicy - -object VerificationPolicies { - - val schemaId = "http://atalaprism.io/schemas/1.0/StudentCredential" - val trustedIssuer1 = "did:example:123456789abcdefghi" - val trustedIssuer2 = "did:example:123456789abcdefghj" - - val VERIFICATION_POLICY = VerificationPolicy( - name = "Trusted Issuer and SchemaID", - description = "Verification Policy with trusted issuer and schemaId", - constraints = listOf( - Constraint( - schemaId = schemaId, - trustedIssuers = listOf( - trustedIssuer1, - trustedIssuer2 - ) - ) - ) - ) -} diff --git a/tests/e2e-tests/src/test/kotlin/features/CommonSteps.kt b/tests/e2e-tests/src/test/kotlin/features/CommonSteps.kt deleted file mode 100644 index 718e1f565d..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/CommonSteps.kt +++ /dev/null @@ -1,153 +0,0 @@ -package features - -import api_models.Connection -import api_models.ConnectionState -import api_models.Credential -import common.Environments -import common.ListenToEvents -import common.Utils -import common.Utils.lastResponseList -import features.connection.ConnectionSteps -import features.did.PublishDidSteps -import features.issue_credentials.IssueCredentialsSteps -import features.multitenancy.EntitySteps -import features.multitenancy.EventsSteps -import features.multitenancy.WalletsSteps -import interactions.Get -import io.cucumber.java.AfterAll -import io.cucumber.java.BeforeAll -import io.cucumber.java.ParameterType -import io.cucumber.java.en.Given -import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.actors.Cast -import net.serenitybdd.screenplay.actors.OnStage -import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.SC_OK - -@BeforeAll -fun initializeIssuerVerifierMultitenantAgent() { - val eventSteps = EventsSteps() - val cast = Cast() - cast.actorNamed("Admin", CallAnApi.at(Environments.ADMIN_AGENT_URL)) - cast.actorNamed("Acme", CallAnApi.at(Environments.ACME_AGENT_URL), ListenToEvents.at(Environments.ACME_AGENT_WEBHOOK_HOST, Environments.ACME_AGENT_WEBHOOK_PORT)) - cast.actorNamed("Bob", CallAnApi.at(Environments.BOB_AGENT_URL), ListenToEvents.at(Environments.BOB_AGENT_WEBHOOK_HOST, Environments.BOB_AGENT_WEBHOOK_PORT)) - cast.actorNamed("Faber", CallAnApi.at(Environments.FABER_AGENT_URL), ListenToEvents.at(Environments.FABER_AGENT_WEBHOOK_HOST, Environments.FABER_AGENT_WEBHOOK_PORT)) - OnStage.setTheStage(cast) - val walletSteps = WalletsSteps() - val entitySteps = EntitySteps() - - // Create issuer wallet and tenant - walletSteps.createNewWallet(cast.actorNamed("Admin"), "issuerWallet") - val issuerEntityId = entitySteps.createNewEntity( - cast.actorNamed("Admin"), walletId = Utils.lastResponseObject("id", String::class), name = "issuer" - ) - entitySteps.addNewApiKeyToEntity(cast.actorNamed("Admin"), issuerEntityId, Environments.ACME_AUTH_KEY) - - // Create verifier wallet - walletSteps.createNewWallet(cast.actorNamed("Admin"), "verifierWallet") - val verifierEntityId = entitySteps.createNewEntity( - cast.actorNamed("Admin"), walletId = Utils.lastResponseObject("id", String::class), name = "verifier" - ) - entitySteps.addNewApiKeyToEntity(cast.actorNamed("Admin"), verifierEntityId, Environments.FABER_AUTH_KEY) - cast.actors.forEach { actor -> - when(actor.name) { - "Acme" -> { - actor.remember("AUTH_KEY", Environments.ACME_AUTH_KEY) - } - "Bob" -> { - actor.remember("AUTH_KEY", Environments.BOB_AUTH_KEY) - } - "Faber" -> { - actor.remember("AUTH_KEY", Environments.FABER_AUTH_KEY) - } - } - } - eventSteps.registerNewWebhook(cast.actorNamed("Acme"), Environments.ACME_AGENT_WEBHOOK_URL) - eventSteps.registerNewWebhook(cast.actorNamed("Faber"), Environments.FABER_AGENT_WEBHOOK_URL) -} - -@AfterAll -fun clearStage() { - OnStage.drawTheCurtain() -} - -class CommonSteps { - @ParameterType(".*") - fun actor(actorName: String): Actor { - return OnStage.theActorCalled(actorName) - } - - @Given("{actor} has an issued credential from {actor}") - fun holderHasIssuedCredentialFromIssuer(holder: Actor, issuer: Actor) { - holder.attemptsTo( - Get.resource("/issue-credentials/records"), - ) - holder.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - val receivedCredential = lastResponseList("contents", Credential::class).findLast { credential -> - credential.protocolState == "CredentialReceived" - } - - if (receivedCredential != null) { - holder.remember("issuedCredential", receivedCredential) - } else { - val publishDidSteps = PublishDidSteps() - val issueSteps = IssueCredentialsSteps() - actorsHaveExistingConnection(issuer, holder) - publishDidSteps.createsUnpublishedDid(holder) - publishDidSteps.createsUnpublishedDid(issuer) - publishDidSteps.hePublishesDidToLedger(issuer) - issueSteps.acmeOffersACredential(issuer, holder, "short") - issueSteps.bobRequestsTheCredential(holder) - issueSteps.acmeIssuesTheCredential(issuer) - issueSteps.bobHasTheCredentialIssued(holder) - } - } - - @Given("{actor} and {actor} have an existing connection") - fun actorsHaveExistingConnection(inviter: Actor, invitee: Actor) { - inviter.attemptsTo( - Get.resource("/connections"), - ) - inviter.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - val inviterConnection = lastResponseList("contents", Connection::class).firstOrNull { - it.label == "Connection with ${invitee.name}" && it.state == ConnectionState.CONNECTION_RESPONSE_SENT - } - - var inviteeConnection: Connection? = null - if (inviterConnection != null) { - invitee.attemptsTo( - Get.resource("/connections"), - ) - invitee.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - inviteeConnection = lastResponseList("contents", Connection::class).firstOrNull { - it.theirDid == inviterConnection.myDid && it.state == ConnectionState.CONNECTION_RESPONSE_RECEIVED - } - } - - if (inviterConnection != null && inviteeConnection != null) { - inviter.remember("connection-with-${invitee.name}", inviterConnection) - invitee.remember("connection-with-${inviter.name}", inviteeConnection) - } else { - val connectionSteps = ConnectionSteps() - connectionSteps.inviterGeneratesAConnectionInvitation(inviter, invitee) - connectionSteps.inviteeReceivesTheConnectionInvitation(invitee, inviter) - connectionSteps.inviteeSendsAConnectionRequestToInviter(invitee, inviter) - connectionSteps.inviterReceivesTheConnectionRequest(inviter) - connectionSteps.inviteeReceivesTheConnectionResponse(invitee) - connectionSteps.inviterAndInviteeHaveAConnection(inviter, invitee) - } - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/connection/ConnectionSteps.kt b/tests/e2e-tests/src/test/kotlin/features/connection/ConnectionSteps.kt deleted file mode 100644 index 3d1d945762..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/connection/ConnectionSteps.kt +++ /dev/null @@ -1,161 +0,0 @@ -package features.connection - -import api_models.* -import common.ListenToEvents -import common.Utils.lastResponseObject -import common.Utils.wait -import interactions.Get -import interactions.Post -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.SC_CREATED -import org.apache.http.HttpStatus.SC_OK -import org.assertj.core.api.Assertions.assertThat -import org.hamcrest.CoreMatchers.* - -class ConnectionSteps { - - @When("{actor} generates a connection invitation to {actor}") - fun inviterGeneratesAConnectionInvitation(inviter: Actor, invitee: Actor) { - // Acme(Issuer) initiates a connection - // and sends it to Bob(Holder) out-of-band, e.g. using QR-code - val connectionLabel = "Connection with ${invitee.name}" - inviter.attemptsTo( - Post.to("/connections") - .with { - it.body("""{"label": "$connectionLabel"}""") - }, - ) - inviter.should( - ResponseConsequence.seeThatResponse { response -> - response.statusCode(SC_CREATED) - response.body("connectionId", notNullValue()) - response.body("createdAt", notNullValue()) - response.body("invitation", notNullValue()) - response.body("label", containsString(connectionLabel)) - response.body("state", containsString(ConnectionState.INVITATION_GENERATED)) - response.body("role", containsString("Inviter")) - }, - ) - // Acme remembers invitation URL to send it out of band to Bob - inviter.remember( - "invitationUrl", - lastResponseObject("", Connection::class) - .invitation.invitationUrl.split("=")[1], - ) - inviter.remember( - "invitation", - lastResponseObject("invitation", Invitation::class), - ) - - // Acme remembers its connection ID for further use - inviter.remember( - "connectionId", - lastResponseObject("", Connection::class) - .connectionId, - ) - inviter.remember("thid", lastResponseObject("", Connection::class).thid) - } - - @When("{actor} receives the connection invitation from {actor}") - fun inviteeReceivesTheConnectionInvitation(invitee: Actor, inviter: Actor) { - // Here out of band transfer of connection QR code is happening - // and Bob (Holder) gets an invitation URL - // they're accepting connection invitation by POST request specifying achieved invitation - // we demonstrate it by Bob remembering invitationUrl that Acme recalls - invitee.remember("invitationUrl", inviter.recall("invitationUrl")) - } - - @When("{actor} sends a connection request to {actor}") - fun inviteeSendsAConnectionRequestToInviter(invitee: Actor, inviter: Actor) { - // Bob accepts connection using achieved out-of-band invitation - invitee.attemptsTo( - Post.to("/connection-invitations") - .with { - it.body("""{"invitation": "${invitee.recall("invitationUrl")}"}""") - }, - ) - val acmeInvitation = inviter.recall("invitation") - invitee.should( - ResponseConsequence.seeThatResponse { response -> - response.statusCode(SC_OK) - response.body("connectionId", notNullValue()) - response.body("createdAt", notNullValue()) - response.body("myDid", notNullValue()) - response.body("theirDid", notNullValue()) - response.body("invitation.from", containsString(acmeInvitation.from)) - response.body("invitation.id", containsString(acmeInvitation.id)) - response.body("invitation.invitationUrl", containsString(acmeInvitation.invitationUrl)) - response.body("invitation.type", containsString(acmeInvitation.type)) - response.body("state", containsString(ConnectionState.CONNECTION_REQUEST_PENDING)) - response.body("role", containsString("Invitee")) - }, - ) - invitee.remember("connectionId", lastResponseObject("", Connection::class).connectionId) - invitee.remember("thid", lastResponseObject("", Connection::class).thid) - } - - @When("{actor} receives the connection request and sends back the response") - fun inviterReceivesTheConnectionRequest(inviter: Actor) { - wait( - { - val lastEvent = ListenToEvents.`as`(inviter).connectionEvents.lastOrNull { - it.data.thid == inviter.recall("thid") - } - lastEvent != null && - lastEvent.data.state == ConnectionState.CONNECTION_RESPONSE_SENT - }, - "Inviter connection didn't reach ${ConnectionState.CONNECTION_RESPONSE_SENT} state", - ) - } - - @When("{actor} receives the connection response") - fun inviteeReceivesTheConnectionResponse(invitee: Actor) { - // Bob (Holder) receives final connection response - wait( - { - val lastEvent = ListenToEvents.`as`(invitee).connectionEvents.lastOrNull { - it.data.thid == invitee.recall("thid") - } - lastEvent != null && - lastEvent.data.state == ConnectionState.CONNECTION_RESPONSE_RECEIVED - }, - "Invitee connection didn't reach ${ConnectionState.CONNECTION_RESPONSE_RECEIVED} state.", - ) - } - - @Then("{actor} and {actor} have a connection") - fun inviterAndInviteeHaveAConnection(inviter: Actor, invitee: Actor) { - // Connection established. Both parties exchanged their DIDs with each other - inviter.attemptsTo( - Get.resource("/connections/${inviter.recall("connectionId")}"), - ) - inviter.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - inviter.remember("connection-with-${invitee.name}", lastResponseObject("", Connection::class)) - - invitee.attemptsTo( - Get.resource("/connections/${invitee.recall("connectionId")}"), - ) - invitee.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - invitee.remember("connection-with-${inviter.name}", lastResponseObject("", Connection::class)) - - assertThat(inviter.recall("connection-with-${invitee.name}").myDid) - .isEqualTo(invitee.recall("connection-with-${inviter.name}").theirDid) - assertThat(inviter.recall("connection-with-${invitee.name}").theirDid) - .isEqualTo(invitee.recall("connection-with-${inviter.name}").myDid) - assertThat(inviter.recall("connection-with-${invitee.name}").state) - .isEqualTo(ConnectionState.CONNECTION_RESPONSE_SENT) - assertThat(invitee.recall("connection-with-${inviter.name}").state) - .isEqualTo(ConnectionState.CONNECTION_RESPONSE_RECEIVED) - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/credential_schemas/CredentialSchemasSteps.kt b/tests/e2e-tests/src/test/kotlin/features/credential_schemas/CredentialSchemasSteps.kt deleted file mode 100644 index 147b8d9a12..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/credential_schemas/CredentialSchemasSteps.kt +++ /dev/null @@ -1,176 +0,0 @@ -package features.credential_schemas - -import api_models.CredentialSchema -import com.fasterxml.jackson.databind.ObjectMapper -import common.TestConstants -import common.Utils.lastResponseObject -import common.Utils.toJsonPath -import io.cucumber.java.PendingException -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import io.restassured.path.json.JsonPath -import net.serenitybdd.screenplay.Actor -import interactions.Get -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.* -import org.hamcrest.CoreMatchers.* -import org.hamcrest.Matchers.containsString -import org.hamcrest.Matchers.emptyString -import java.util.* - -class CredentialSchemasSteps { - - @When("{actor} creates a new credential schema") - fun acmeCreatesANewCredentialSchema(actor: Actor) { - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.copy(author = actor.recall("shortFormDid"))) - }, - ) - } - - @Then("{actor} sees new credential schema is available") - fun newCredentialSchemaIsAvailable(actor: Actor) { - actor.should(ResponseConsequence.seeThatResponse("New schema created") { - it.statusCode(SC_CREATED) - it.body("guid", not(emptyString())) - it.body("id", not(emptyString())) - it.body("longId", not(emptyString())) - it.body("authored", not(emptyString())) - it.body("kind", containsString("CredentialSchema")) - it.body("name", containsString(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.name)) - it.body("description", containsString(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.description)) - it.body("version", containsString(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.version)) - it.body("type", equalTo(TestConstants.CREDENTIAL_SCHEMAS.CREDENTIAL_SCHEMA_TYPE)) - TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.tags!!.forEach { tag -> - it.body("tags", hasItem(tag)) - } - it.body( - "schema.\$id", - equalTo(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.schema!!.get("\$id").asText()) - ) - - it.body( - "schema", equalTo>( - JsonPath( - ObjectMapper().writeValueAsString( - TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA.schema - ) - ).getMap("") - ) - ) - }) - } - - @When("{actor} creates {int} new schemas") - fun acmeCreatesMultipleSchemas(actor: Actor, numberOfSchemas: Int) { - val createdSchemas: MutableList = mutableListOf() - repeat(numberOfSchemas) { i: Int -> - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body( - TestConstants.CREDENTIAL_SCHEMAS.generate_with_name_suffix_and_author( - i.toString(), - actor.recall("shortFormDid") - ) - ) - }, - ) - actor.should( - ResponseConsequence.seeThatResponse("New schema created") { - it.statusCode(SC_CREATED) - }, - ) - createdSchemas.add(lastResponseObject("", CredentialSchema::class)) - } - actor.remember("createdSchemas", createdSchemas) - } - - @Then("{actor} can access all of them one by one") - fun theyCanBeAccessedWithPagination(actor: Actor) { - actor.recall>("createdSchemas").forEach { schema -> - actor.attemptsTo( - Get.resource("/schema-registry/schemas/${schema.guid}"), - ) - actor.should( - ResponseConsequence.seeThatResponse("Schema achieved") { - it.statusCode(SC_OK) - }, - ) - } - } - - @When("{actor} creates a new schema with some id") - fun acmeCreatesANewSchemaWithFixedId(actor: Actor) { - val wrongSchema = TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA - wrongSchema.guid = TestConstants.RANDOM_CONSTAND_UUID - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body(wrongSchema) - }, - ) - actor.should( - ResponseConsequence.seeThatResponse("New schema created") { - it.statusCode(SC_CREATED) - }, - ) - } - - @When("{actor} tries to create a new schema with identical id") - fun acmeTriesToCreateANewSchemaWithSameId(actor: Actor) { - val wrongSchema = TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA - wrongSchema.guid = TestConstants.RANDOM_CONSTAND_UUID - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body(wrongSchema) - }, - ) - } - - @Then("{actor} sees the request failure with identical id error") - fun idDuplicateErrorIsThrown(actor: Actor) { - try { - actor.should( - ResponseConsequence.seeThatResponse("New schema creation error: same UUID") { - it.statusCode(SC_BAD_REQUEST) - }, - ) - } catch (err: AssertionError) { - println(err.message) - throw PendingException("BUG: New credential schema CAN be created with same UUID.") - } - } - - @When("{actor} tries to create a new schema with {word} in field {word}") - fun acmeTriesToCreateANewSchemaWithField(actor: Actor, value: String, field: String) { - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body( - toJsonPath(TestConstants.CREDENTIAL_SCHEMAS.STUDENT_SCHEMA).set(field, value).jsonString(), - ) - }, - ) - } - - @When("{actor} tries to get schemas with {int} in parameter {word}") - fun acmeTriesToCreateANewSchemaWithParameter(actor: Actor, value: Int, parameter: String) { - actor.attemptsTo( - Get.resource("/schema-registry/schemas?$parameter=$value"), - ) - } - - @Then("{actor} sees the request with status {int}") - fun heSeesTheRequestFailureWithErrorStatus(actor: Actor, errorStatusCode: Int) { - try { - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(errorStatusCode) - }, - ) - } catch (err: AssertionError) { - println(err.message) - throw PendingException("BUG: credential schemas CAN be accessed with negative limit and offset.") - } - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt b/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt deleted file mode 100644 index f95cf7f6da..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/did/PublishDidSteps.kt +++ /dev/null @@ -1,153 +0,0 @@ -package features.did - -import api_models.* -import common.ListenToEvents -import common.TestConstants -import common.Utils.lastResponseList -import common.Utils.lastResponseObject -import common.Utils.wait -import io.cucumber.java.en.Given -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import net.serenitybdd.screenplay.Actor -import interactions.Get -import interactions.Post -import net.serenitybdd.rest.SerenityRest -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.* -import org.assertj.core.api.Assertions.assertThat -import org.hamcrest.Matchers.* - -class PublishDidSteps { - - @Given("{actor} have published PRISM DID") - fun actorHavePublishedPrismDid(actor: Actor) { - actor.attemptsTo( - Get.resource("/did-registrar/dids"), - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - val publishedDids = lastResponseList("contents", ManagedDid::class).filter { - it.status == ManagedDidStatuses.PUBLISHED - } - val did = publishedDids.firstOrNull { - actor.attemptsTo( - Get.resource("/dids/${it.did}"), - ) - lastResponseObject("didDocumentMetadata.deactivated", String::class) == "false" - } - if (did == null) { - createsUnpublishedDid(actor) - hePublishesDidToLedger(actor) - } else { - actor.remember("shortFormDid", did.did) - } - } - - @Given("{actor} creates unpublished DID") - fun createsUnpublishedDid(actor: Actor) { - val publicKeys = listOf( - TestConstants.PRISM_DID_AUTH_KEY, - TestConstants.PRISM_DID_ASSERTION_KEY, - ) - val services = listOf( - TestConstants.PRISM_DID_SERVICE, - TestConstants.PRISM_DID_SERVICE_FOR_UPDATE, - TestConstants.PRISM_DID_SERVICE_TO_REMOVE, - ) - val documentTemplate = DocumentTemplate(publicKeys, services) - actor.attemptsTo( - Post.to("/did-registrar/dids") - .with { - it.body(CreatePrismDidRequest(documentTemplate)) - }, - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_CREATED) - it.body("longFormDid", not(emptyString())) - }, - ) - val longFormDid = lastResponseObject("longFormDid", String::class) - actor.remember("longFormDid", longFormDid) - - actor.attemptsTo( - Get.resource("/did-registrar/dids/$longFormDid"), - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - actor.remember( - "shortFormDid", - lastResponseObject("", ManagedDid::class).did, - ) - } - - @When("{actor} publishes DID to ledger") - fun hePublishesDidToLedger(actor: Actor) { - actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/publications"), - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_ACCEPTED) - it.body("scheduledOperation.didRef", not(emptyString())) - it.body("scheduledOperation.id", not(emptyString())) - }, - ) - wait( - { - val didEvent = - ListenToEvents.`as`(actor).didEvents.lastOrNull { - it.data.did == actor.recall("shortFormDid") - } - didEvent != null && didEvent.data.status == ManagedDidStatuses.PUBLISHED - }, - "ERROR: DID was not published to ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, - ) - actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - it.body("didDocument.id", equalTo(actor.recall("shortFormDid"))) - }, - ) - } - - @Then("{actor} resolves DID document corresponds to W3C standard") - fun heSeesDidDocumentCorrespondsToW3cStandard(actor: Actor) { - val didDocument = lastResponseObject("", DidResolutionResult::class).didDocument!! - assertThat(didDocument) - .hasFieldOrProperty("assertionMethod") - .hasFieldOrProperty("authentication") - .hasFieldOrProperty("capabilityInvocation") - .hasFieldOrProperty("controller") - .hasFieldOrProperty("id") - .hasFieldOrProperty("keyAgreement") - .hasFieldOrProperty("service") - .hasFieldOrProperty("verificationMethod") - - val shortFormDid = actor.recall("shortFormDid") - - assertThat(didDocument.id == shortFormDid) - - assertThat(didDocument.authentication!![0]) - .isEqualTo("$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}") - - assertThat(didDocument.verificationMethod!![0]) - .hasFieldOrPropertyWithValue("controller", shortFormDid) - .hasFieldOrProperty("publicKeyJwk") - - assertThat(lastResponseObject("", DidResolutionResult::class).didDocumentMetadata!!) - .hasFieldOrPropertyWithValue("deactivated", false) - .hasFieldOrProperty("canonicalId") - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt b/tests/e2e-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt deleted file mode 100644 index 81acb9a978..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt +++ /dev/null @@ -1,19 +0,0 @@ -package features.multitenancy - -import api_models.RegisterWebhookRequest -import interactions.Post -import net.serenitybdd.rest.SerenityRest -import net.serenitybdd.screenplay.Actor - -class EventsSteps { - fun registerNewWebhook(actor: Actor, webhookUrl: String) { - actor.attemptsTo( - Post.to("/events/webhooks") - .with { - it.body( - RegisterWebhookRequest(url = webhookUrl) - ) - }, - ) - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/present_proof/PresentProofSteps.kt b/tests/e2e-tests/src/test/kotlin/features/present_proof/PresentProofSteps.kt deleted file mode 100644 index 3641b9de23..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/present_proof/PresentProofSteps.kt +++ /dev/null @@ -1,133 +0,0 @@ -package features.present_proof - -import api_models.* -import common.ListenToEvents -import common.Utils.lastResponseObject -import common.Utils.wait -import interactions.Get -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import net.serenitybdd.screenplay.Actor -import interactions.Post -import interactions.Patch -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.SC_CREATED -import org.apache.http.HttpStatus.SC_OK - -class PresentProofSteps { - - var proofEvent: PresentationEvent? = null - - @When("{actor} sends a request for proof presentation to {actor}") - fun faberSendsARequestForProofPresentationToBob(faber: Actor, bob: Actor) { - faber.attemptsTo( - Post.to("/present-proof/presentations") - .with { - it.body( - """ - { - "description":"Request presentation of credential", - "connectionId": "${faber.recall("connection-with-${bob.name}").connectionId}", - "options":{ - "challenge": "11c91493-01b3-4c4d-ac36-b336bab5bddf", - "domain": "https://example-verifier.com" - }, - "proofs":[ - { - "schemaId": "https://schema.org/Person", - "trustIssuers": [ - "did:web:atalaprism.io/users/testUser" - ] - } - ] - } - """.trimIndent(), - ) - }, - ) - faber.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_CREATED) - }, - ) - - val presentationId = lastResponseObject("", PresentationProof::class).presentationId - faber.remember("presentationId", presentationId) - faber.attemptsTo( - Get.resource("/present-proof/presentations/${presentationId}"), - ) - faber.should( - ResponseConsequence.seeThatResponse("Get presentations") { - it.statusCode(SC_OK) - }, - ) - faber.remember("thid", lastResponseObject("", PresentationProof::class).thid) - bob.remember("thid", lastResponseObject("", PresentationProof::class).thid) - } - - @When("{actor} receives the request") - fun bobReceivesTheRequest(bob: Actor) { - wait( - { - proofEvent = ListenToEvents.`as`(bob).presentationEvents.lastOrNull { - it.data.thid == bob.recall("thid") - } - proofEvent != null && - proofEvent!!.data.status == PresentationProofStatus.REQUEST_RECEIVED - }, - "ERROR: Bob did not achieve any presentation request!", - ) - bob.remember("presentationId", proofEvent!!.data.presentationId) - } - - @When("{actor} makes the presentation of the proof to {actor}") - fun bobMakesThePresentationOfTheProof(bob: Actor, faber: Actor) { - bob.attemptsTo( - Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { - it.body( - """ - { "action": "request-accept", "proofId": ["${bob.recall("issuedCredential").recordId}"] } - """.trimIndent(), - ) - }, - ) - } - - @When("{actor} rejects the proof") - fun bobRejectsProof(bob: Actor) { - bob.attemptsTo( - Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { - it.body("""{ "action": "request-reject" }""") - }, - ) - } - - @Then("{actor} sees the proof is rejected") - fun bobSeesProofIsRejected(bob: Actor) { - wait( - { - proofEvent = ListenToEvents.`as`(bob).presentationEvents.lastOrNull { - it.data.thid == bob.recall("thid") - } - proofEvent != null && - proofEvent!!.data.status == PresentationProofStatus.REQUEST_REJECTED - }, - "ERROR: Faber did not receive presentation from Bob!", - ) - } - - @Then("{actor} has the proof verified") - fun faberHasTheProofVerified(faber: Actor) { - wait( - { - proofEvent = ListenToEvents.`as`(faber).presentationEvents.lastOrNull { - it.data.thid == faber.recall("thid") - } - - proofEvent != null && - proofEvent!!.data.status == PresentationProofStatus.PRESENTATION_VERIFIED - }, - "ERROR: presentation did not achieve PresentationVerified state!", - ) - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/system/SystemSteps.kt b/tests/e2e-tests/src/test/kotlin/features/system/SystemSteps.kt deleted file mode 100644 index 9835c7246b..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/system/SystemSteps.kt +++ /dev/null @@ -1,36 +0,0 @@ -package features.system - -import api_models.HealthInfo -import common.Utils.lastResponseObject -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import net.serenitybdd.screenplay.Actor -import interactions.Get -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus.SC_OK -import org.assertj.core.api.Assertions.assertThat - -class SystemSteps { - @When("{actor} makes a request to the health endpoint") - fun actorRequestsHealthEndpoint(actor: Actor) { - actor.attemptsTo( - Get.resource("/_system/health"), - ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_OK) - }, - ) - val healthResponse = lastResponseObject("", HealthInfo::class) - assertThat(healthResponse) - .hasFieldOrProperty("version") - .hasNoNullFieldsOrProperties() - actor.remember("version", healthResponse.version) - } - - @Then("{actor} knows what version of the service is running") - fun actorUnderstandsVersion(actor: Actor) { - assertThat(actor.recall("version")) - .isNotBlank() - } -} diff --git a/tests/e2e-tests/src/test/kotlin/features/verification_policies/VerificationPoliciesSteps.kt b/tests/e2e-tests/src/test/kotlin/features/verification_policies/VerificationPoliciesSteps.kt deleted file mode 100644 index 6f5d95280a..0000000000 --- a/tests/e2e-tests/src/test/kotlin/features/verification_policies/VerificationPoliciesSteps.kt +++ /dev/null @@ -1,96 +0,0 @@ -package features.verification_policies - -import api_models.VerificationPolicy -import api_models.VerificationPolicyInput -import common.TestConstants -import io.cucumber.java.en.Then -import io.cucumber.java.en.When -import net.serenitybdd.rest.SerenityRest -import net.serenitybdd.screenplay.Actor -import interactions.Put -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence -import org.apache.http.HttpStatus -import org.hamcrest.CoreMatchers -import org.hamcrest.Matchers -import java.util.* - - -class VerificationPoliciesSteps { - - @When("{actor} creates a new verification policy") - fun acmeCreatesANewVerificationPolicy(actor: Actor) { - actor.attemptsTo( - Post.to("/verification/policies").with { - it.body(TestConstants.VERIFICATION_POLICIES.VERIFICATION_POLICY) - }, - ) - } - - @Then("{actor} sees new verification policy is available") - fun newVerificationPolicyIsAvailable(actor: Actor) { - actor.should(ResponseConsequence.seeThatResponse("New policy created") { - it.statusCode(HttpStatus.SC_CREATED) - //it.body("", CoreMatchers.`is`(Matchers.emptyString())) - it.body("id", CoreMatchers.not(Matchers.emptyString())) - it.body("nonce", CoreMatchers.not(Matchers.emptyString())) - it.body("kind", Matchers.containsString("VerificationPolicy")) - it.body( - "name", - Matchers.containsString(TestConstants.VERIFICATION_POLICIES.VERIFICATION_POLICY.name) - ) - it.body( - "description", - Matchers.containsString(TestConstants.VERIFICATION_POLICIES.VERIFICATION_POLICY.description) - ) - TestConstants.VERIFICATION_POLICIES.VERIFICATION_POLICY.constraints!!.forEach { constraint -> - it.body("constraints.schemaId", CoreMatchers.hasItem(constraint.schemaId)) - it.body("constraints.trustedIssuers", CoreMatchers.hasItems(constraint.trustedIssuers!!)) - } - }) - val policy = SerenityRest.lastResponse().`as`(VerificationPolicy::class.java) - actor.remember("policy", policy) - } - - @When("{actor} updates a new verification policy") - fun acmeUpdatesAVerificationPolicy(actor: Actor) { - val policy = actor.recall("policy") - val updatePolicyInput = VerificationPolicyInput( - name = policy.name, - description = "updated description + ${UUID.randomUUID()}", - constraints = policy.constraints - ) - actor.attemptsTo( - Put.to("/verification/policies/${policy.id}?nonce=${policy.nonce}").with { - it.body(updatePolicyInput) - }, - ) - actor.remember("updatedPolicyInput", updatePolicyInput) - } - - @Then("{actor} sees the updated verification policy is available") - fun updatedVerificationPolicyIsAvailable(actor: Actor) { - val updatedPolicy = actor.forget("policy") - val updatePolicyInput = actor.forget("updatedPolicyInput") - actor.should(ResponseConsequence.seeThatResponse("Verification policy is updated") { - it.statusCode(HttpStatus.SC_OK) - it.body("id", CoreMatchers.`is`(Matchers.equalTo(updatedPolicy.id))) - it.body("nonce", CoreMatchers.not(Matchers.emptyString())) - it.body("kind", Matchers.containsString("VerificationPolicy")) - it.body( - "name", - Matchers.containsString(updatePolicyInput.name) - ) - it.body( - "description", - Matchers.containsString(updatePolicyInput.description) - ) - updatePolicyInput.constraints!!.forEach { constraint -> - it.body("constraints.schemaId", CoreMatchers.hasItem(constraint.schemaId)) - it.body("constraints.trustedIssuers", CoreMatchers.hasItems(constraint.trustedIssuers!!)) - } - }) - val policy = SerenityRest.lastResponse().`as`(VerificationPolicy::class.java) - actor.remember("policy", policy) - } -} diff --git a/tests/e2e-tests/src/test/resources/cucumber.properties b/tests/e2e-tests/src/test/resources/cucumber.properties deleted file mode 100644 index b48dd63bf1..0000000000 --- a/tests/e2e-tests/src/test/resources/cucumber.properties +++ /dev/null @@ -1 +0,0 @@ -cucumber.publish.quiet=true diff --git a/tests/e2e-tests/.gitignore b/tests/integration-tests/.gitignore similarity index 100% rename from tests/e2e-tests/.gitignore rename to tests/integration-tests/.gitignore diff --git a/tests/integration-tests/build.gradle.kts b/tests/integration-tests/build.gradle.kts new file mode 100644 index 0000000000..db95650174 --- /dev/null +++ b/tests/integration-tests/build.gradle.kts @@ -0,0 +1,74 @@ +plugins { + idea + id("org.jetbrains.kotlin.jvm") version "1.9.0" + id("net.serenity-bdd.serenity-gradle-plugin") version "4.0.14" + id("org.jlleitschuh.gradle.ktlint") version "11.5.0" +} + +repositories { + mavenCentral() + maven { + url = uri("https://maven.pkg.github.com/input-output-hk/atala-automation/") + credentials { + username = System.getenv("ATALA_GITHUB_ACTOR") + password = System.getenv("ATALA_GITHUB_TOKEN") + } + } + maven { + url = uri("https://maven.pkg.github.com/hyperledger-labs/open-enterprise-agent/") + credentials { + username = System.getenv("ATALA_GITHUB_ACTOR") + password = System.getenv("ATALA_GITHUB_TOKEN") + } + } +} + +dependencies { + // Logging + implementation("org.slf4j:slf4j-log4j12:2.0.5") + // Beautify async waits + implementation("org.awaitility:awaitility-kotlin:4.2.0") + // Test engines and reports + testImplementation("junit:junit:4.13.2") + implementation("net.serenity-bdd:serenity-core:4.0.14") + implementation("net.serenity-bdd:serenity-cucumber:4.0.14") + implementation("net.serenity-bdd:serenity-screenplay-rest:4.0.14") + testImplementation("net.serenity-bdd:serenity-ensure:4.0.14") + // HTTP listener + implementation("io.ktor:ktor-server-netty:2.3.0") + implementation("io.ktor:ktor-client-apache:2.3.0") + // RestAPI client + implementation("io.iohk.atala.prism:prism-kotlin-client:1.15.0") + // Test helpers library + testImplementation("io.iohk.atala:atala-automation:0.3.0") + // Hoplite for configuration + implementation("com.sksamuel.hoplite:hoplite-core:2.7.5") + implementation("com.sksamuel.hoplite:hoplite-hocon:2.7.5") +} + +buildscript { + dependencies { + classpath("net.serenity-bdd:serenity-single-page-report:4.0.14") + classpath("net.serenity-bdd:serenity-json-summary-report:4.0.14") + } +} + +/** + * Add HTML one-pager and JSON summary report to be produced + */ +serenity { + reports = listOf("single-page-html", "json-summary") +} + +tasks.test { + testLogging.showStandardStreams = true + systemProperty("cucumber.filter.tags", System.getProperty("cucumber.filter.tags")) +} + +kotlin { + jvmToolchain(19) +} + +ktlint { + disabledRules.set(setOf("no-wildcard-imports")) +} diff --git a/tests/e2e-tests/gradle.properties b/tests/integration-tests/gradle.properties similarity index 100% rename from tests/e2e-tests/gradle.properties rename to tests/integration-tests/gradle.properties diff --git a/tests/e2e-tests/gradle/wrapper/gradle-wrapper.jar b/tests/integration-tests/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from tests/e2e-tests/gradle/wrapper/gradle-wrapper.jar rename to tests/integration-tests/gradle/wrapper/gradle-wrapper.jar diff --git a/tests/e2e-tests/gradle/wrapper/gradle-wrapper.properties b/tests/integration-tests/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from tests/e2e-tests/gradle/wrapper/gradle-wrapper.properties rename to tests/integration-tests/gradle/wrapper/gradle-wrapper.properties diff --git a/tests/e2e-tests/gradlew b/tests/integration-tests/gradlew similarity index 100% rename from tests/e2e-tests/gradlew rename to tests/integration-tests/gradlew diff --git a/tests/e2e-tests/gradlew.bat b/tests/integration-tests/gradlew.bat similarity index 100% rename from tests/e2e-tests/gradlew.bat rename to tests/integration-tests/gradlew.bat diff --git a/tests/e2e-tests/serenity.properties b/tests/integration-tests/serenity.properties similarity index 77% rename from tests/e2e-tests/serenity.properties rename to tests/integration-tests/serenity.properties index a4b2f36eb0..52ed622b2f 100644 --- a/tests/e2e-tests/serenity.properties +++ b/tests/integration-tests/serenity.properties @@ -1,4 +1,4 @@ -serenity.project.name=PRISM agent e2e tests +serenity.project.name=Open Enterprise Agent Integration tests serenity.reports.show.step.details=true serenity.console.colors=true simplified.stack.traces=false diff --git a/tests/integration-tests/settings.gradle.kts b/tests/integration-tests/settings.gradle.kts new file mode 100644 index 0000000000..e57032400b --- /dev/null +++ b/tests/integration-tests/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "integration-tests" diff --git a/tests/integration-tests/src/main/kotlin/models/Events.kt b/tests/integration-tests/src/main/kotlin/models/Events.kt new file mode 100644 index 0000000000..0295c3a713 --- /dev/null +++ b/tests/integration-tests/src/main/kotlin/models/Events.kt @@ -0,0 +1,48 @@ +package models + +import com.google.gson.JsonElement +import com.google.gson.annotations.SerializedName +import io.iohk.atala.prism.models.Connection +import io.iohk.atala.prism.models.IssueCredentialRecord +import io.iohk.atala.prism.models.ManagedDID +import io.iohk.atala.prism.models.PresentationStatus + +data class Event( + @SerializedName("type") var type: String, + @SerializedName("id") var id: String, + @SerializedName("ts") var ts: String, + @SerializedName("data") var data: JsonElement, + @SerializedName("walletId") var walletId: String +) + +data class ConnectionEvent( + @SerializedName("type") var type: String, + @SerializedName("id") var id: String, + @SerializedName("ts") var ts: String, + @SerializedName("data") var data: Connection, + @SerializedName("walletId") var walletId: String +) + +data class CredentialEvent( + @SerializedName("type") var type: String, + @SerializedName("id") var id: String, + @SerializedName("ts") var ts: String, + @SerializedName("data") var data: IssueCredentialRecord, + @SerializedName("walletId") var walletId: String +) + +data class PresentationEvent( + @SerializedName("type") var type: String, + @SerializedName("id") var id: String, + @SerializedName("ts") var ts: String, + @SerializedName("data") var data: PresentationStatus, + @SerializedName("walletId") var walletId: String +) + +data class DidEvent( + @SerializedName("type") var type: String, + @SerializedName("id") var id: String, + @SerializedName("ts") var ts: String, + @SerializedName("data") var data: ManagedDID, + @SerializedName("walletId") var walletId: String +) diff --git a/tests/integration-tests/src/main/kotlin/models/Schema.kt b/tests/integration-tests/src/main/kotlin/models/Schema.kt new file mode 100644 index 0000000000..59db1c85a7 --- /dev/null +++ b/tests/integration-tests/src/main/kotlin/models/Schema.kt @@ -0,0 +1,20 @@ +package models + +import com.google.gson.annotations.SerializedName + +data class Schema( + @SerializedName("\$id") + var id: String = "", + + @SerializedName("\$schema") + var schema: String = "", + + @SerializedName("\$description") + var description: String = "", + + @SerializedName("type") + var type: String = "", + + @SerializedName("properties") + val properties: MutableMap = mutableMapOf() +) diff --git a/tests/integration-tests/src/main/kotlin/models/SchemaProperty.kt b/tests/integration-tests/src/main/kotlin/models/SchemaProperty.kt new file mode 100644 index 0000000000..676d47151b --- /dev/null +++ b/tests/integration-tests/src/main/kotlin/models/SchemaProperty.kt @@ -0,0 +1,8 @@ +package models + +import com.google.gson.annotations.SerializedName + +data class SchemaProperty( + @SerializedName("type") + var type: String = "" +) diff --git a/tests/e2e-tests/src/test/kotlin/common/ListenToEvents.kt b/tests/integration-tests/src/test/kotlin/common/ListenToEvents.kt similarity index 61% rename from tests/e2e-tests/src/test/kotlin/common/ListenToEvents.kt rename to tests/integration-tests/src/test/kotlin/common/ListenToEvents.kt index b221e3ce12..3efae51c49 100644 --- a/tests/e2e-tests/src/test/kotlin/common/ListenToEvents.kt +++ b/tests/integration-tests/src/test/kotlin/common/ListenToEvents.kt @@ -1,6 +1,7 @@ package common -import api_models.* +import com.google.gson.GsonBuilder +import io.iohk.atala.automation.restassured.CustomGsonObjectMapperFactory import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.engine.* @@ -8,19 +9,21 @@ import io.ktor.server.netty.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json +import models.* import net.serenitybdd.screenplay.Ability import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.HasTeardown -import java.lang.IllegalArgumentException +import java.net.URL +import java.time.OffsetDateTime open class ListenToEvents( - private val host: String, - private val port: Int, -): Ability, HasTeardown { + private val url: URL +) : Ability, HasTeardown { private val server: ApplicationEngine + private val gson = GsonBuilder() + .registerTypeAdapter(OffsetDateTime::class.java, CustomGsonObjectMapperFactory.OffsetDateTimeDeserializer()) + .create() var connectionEvents: MutableList = mutableListOf() var credentialEvents: MutableList = mutableListOf() @@ -31,13 +34,13 @@ open class ListenToEvents( application.routing { post("/") { val eventString = call.receiveText() - val event = Json.decodeFromString(eventString) + val event = gson.fromJson(eventString, Event::class.java) when (event.type) { - TestConstants.EVENT_TYPE_CONNECTION_UPDATED -> connectionEvents.add(Json.decodeFromString(eventString)) - TestConstants.EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED -> credentialEvents.add(Json.decodeFromString(eventString)) - TestConstants.EVENT_TYPE_PRESENTATION_UPDATED -> presentationEvents.add(Json.decodeFromString(eventString)) + TestConstants.EVENT_TYPE_CONNECTION_UPDATED -> connectionEvents.add(gson.fromJson(eventString, ConnectionEvent::class.java)) + TestConstants.EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED -> credentialEvents.add(gson.fromJson(eventString, CredentialEvent::class.java)) + TestConstants.EVENT_TYPE_PRESENTATION_UPDATED -> presentationEvents.add(gson.fromJson(eventString, PresentationEvent::class.java)) TestConstants.EVENT_TYPE_DID_STATUS_UPDATED -> { - didEvents.add(Json.decodeFromString(eventString)) + didEvents.add(gson.fromJson(eventString, DidEvent::class.java)) } else -> { throw IllegalArgumentException("ERROR: unknown event type ${event.type}") @@ -49,8 +52,8 @@ open class ListenToEvents( } companion object { - fun at(host: String, port: Int): ListenToEvents { - return ListenToEvents(host, port) + fun at(url: URL): ListenToEvents { + return ListenToEvents(url) } fun `as`(actor: Actor): ListenToEvents { @@ -61,14 +64,15 @@ open class ListenToEvents( init { server = embeddedServer( Netty, - port = port, - host = if (host == "host.docker.internal") "0.0.0.0" else host, - module = {route(this)}) + port = url.port, + host = if (url.host == "host.docker.internal") "0.0.0.0" else url.host, + module = { route(this) } + ) .start(wait = false) } override fun toString(): String { - return "Listen HTTP port at ${host}:${port}" + return "Listen HTTP port at $url" } override fun tearDown() { diff --git a/tests/integration-tests/src/test/kotlin/common/TestConstants.kt b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt new file mode 100644 index 0000000000..349f7a69d7 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt @@ -0,0 +1,90 @@ +package common + +import io.iohk.atala.prism.models.* +import models.Schema +import models.SchemaProperty +import java.time.Duration +import java.util.* + +object TestConstants { + val TEST_VERIFICATION_POLICY = VerificationPolicyInput( + name = "Trusted Issuer and SchemaID", + description = "Verification Policy with trusted issuer and schemaId", + constraints = listOf( + VerificationPolicyConstraint( + schemaId = "http://atalaprism.io/schemas/1.0/StudentCredential", + trustedIssuers = listOf( + "did:example:123456789abcdefghi", + "did:example:123456789abcdefghj" + ) + ) + ) + ) + val CREDENTIAL_SCHEMA_TYPE = "https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json" + + val SCHEMA_TYPE = "https://json-schema.org/draft/2020-12/schema" + + val jsonSchema = Schema( + id = "https://example.com/student-schema-1.0", + schema = SCHEMA_TYPE, + description = "Student schema", + type = "object", + properties = mutableMapOf( + "name" to SchemaProperty(type = "string"), + "age" to SchemaProperty(type = "integer") + ) + ) + + fun generate_with_name_suffix_and_author(suffix: String, author: String): CredentialSchemaInput { + return CredentialSchemaInput( + author = author, + name = "${UUID.randomUUID()} $suffix", + description = "Simple student credentials schema", + type = CREDENTIAL_SCHEMA_TYPE, + schema = jsonSchema, + tags = listOf("school", "students"), + version = "1.0.0" + ) + } + + val STUDENT_SCHEMA = CredentialSchemaInput( + author = "did:prism:agent", + name = UUID.randomUUID().toString(), + description = "Simple student credentials schema", + type = CREDENTIAL_SCHEMA_TYPE, + schema = jsonSchema, + tags = listOf("school", "students"), + version = "1.0.0" + ) + val RANDOM_CONSTAND_UUID = UUID.randomUUID().toString() + val DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN = Duration.ofSeconds(60L) + val PRISM_DID_AUTH_KEY = ManagedDIDKeyTemplate("auth-1", Purpose.authentication) + val PRISM_DID_ASSERTION_KEY = ManagedDIDKeyTemplate("assertion-1", Purpose.assertionMethod) + val PRISM_DID_UPDATE_NEW_AUTH_KEY = ManagedDIDKeyTemplate("auth-2", Purpose.authentication) + val PRISM_DID_SERVICE = Service( + "https://foo.bar.com", + listOf("LinkedDomains"), + Json("https://foo.bar.com/") + ) + val PRISM_DID_SERVICE_FOR_UPDATE = Service( + "https://update.com", + listOf("LinkedDomains"), + Json("https://update.com/") + ) + val PRISM_DID_SERVICE_TO_REMOVE = Service( + "https://remove.com", + listOf("LinkedDomains"), + Json("https://remove.com/") + ) + val PRISM_DID_UPDATE_NEW_SERVICE_URL = "https://bar.foo.com/" + val PRISM_DID_UPDATE_NEW_SERVICE = Service( + "https://new.service.com", + listOf("LinkedDomains"), + Json("https://new.service.com/") + ) + val EVENT_TYPE_CONNECTION_UPDATED = "ConnectionUpdated" + val EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED = "IssueCredentialRecordUpdated" + val EVENT_TYPE_PRESENTATION_UPDATED = "PresentationUpdated" + val EVENT_TYPE_DID_STATUS_UPDATED = "DIDStatusUpdated" + val WRONG_SEED = "wrong seed" +} diff --git a/tests/integration-tests/src/test/kotlin/common/Utils.kt b/tests/integration-tests/src/test/kotlin/common/Utils.kt new file mode 100644 index 0000000000..2ccbd5b5c1 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/Utils.kt @@ -0,0 +1,29 @@ +package common + +import org.awaitility.Awaitility +import org.awaitility.core.ConditionTimeoutException +import org.awaitility.kotlin.withPollInterval +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().withPollInterval(poolInterval) + .pollInSameThread() + .atMost(timeout) + .until { + blockToWait() + } + } catch (err: ConditionTimeoutException) { + throw ConditionTimeoutException( + errorMessage + ) + } + } +} diff --git a/tests/integration-tests/src/test/kotlin/config/AgentConf.kt b/tests/integration-tests/src/test/kotlin/config/AgentConf.kt new file mode 100644 index 0000000000..dacb1b5f33 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/config/AgentConf.kt @@ -0,0 +1,10 @@ +package config + +import com.sksamuel.hoplite.ConfigAlias +import java.net.URL + +data class AgentConf( + val url: URL, + @ConfigAlias("webhook_url") val webhookUrl: URL?, + var apikey: String? +) diff --git a/tests/integration-tests/src/test/kotlin/config/Config.kt b/tests/integration-tests/src/test/kotlin/config/Config.kt new file mode 100644 index 0000000000..c4abe8b62d --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/config/Config.kt @@ -0,0 +1,9 @@ +package config + +data class Config( + val global: GlobalConf, + val issuer: AgentConf, + val holder: AgentConf, + val verifier: AgentConf, + val admin: AgentConf +) diff --git a/tests/integration-tests/src/test/kotlin/config/GlobalConf.kt b/tests/integration-tests/src/test/kotlin/config/GlobalConf.kt new file mode 100644 index 0000000000..b0cda15c3b --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/config/GlobalConf.kt @@ -0,0 +1,9 @@ +package config + +import com.sksamuel.hoplite.ConfigAlias + +data class GlobalConf( + @ConfigAlias("auth_required") val authRequired: Boolean, + @ConfigAlias("auth_header") val authHeader: String, + @ConfigAlias("admin_auth_header") val adminAuthHeader: String +) diff --git a/tests/integration-tests/src/test/kotlin/features/CommonSteps.kt b/tests/integration-tests/src/test/kotlin/features/CommonSteps.kt new file mode 100644 index 0000000000..9fe6a62393 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/CommonSteps.kt @@ -0,0 +1,252 @@ +package features + +import com.sksamuel.hoplite.ConfigLoader +import common.ListenToEvents +import config.Config +import features.connection.ConnectionSteps +import features.credentials.IssueCredentialsSteps +import features.did.PublishDidSteps +import features.multitenancy.EventsSteps +import interactions.Get +import io.cucumber.java.AfterAll +import io.cucumber.java.BeforeAll +import io.cucumber.java.ParameterType +import io.cucumber.java.en.Given +import io.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.* +import io.restassured.RestAssured +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.actors.Cast +import net.serenitybdd.screenplay.actors.OnStage +import net.serenitybdd.screenplay.rest.abilities.CallAnApi +import org.apache.http.HttpStatus +import org.apache.http.HttpStatus.SC_OK +import java.util.* +import kotlin.random.Random + +@OptIn(ExperimentalStdlibApi::class) +@BeforeAll +fun initializeIssuerVerifierMultitenantAgent() { + val eventSteps = EventsSteps() + val cast = Cast() + + val config = ConfigLoader().loadConfigOrThrow("/tests.conf") + + cast.actorNamed("Admin", CallAnApi.at(config.admin.url.toExternalForm())) + cast.actorNamed( + "Acme", + CallAnApi.at(config.issuer.url.toExternalForm()), + ListenToEvents.at(config.issuer.webhookUrl!!) + ) + cast.actorNamed( + "Bob", + CallAnApi.at(config.holder.url.toExternalForm()), + ListenToEvents.at(config.holder.webhookUrl!!) + ) + cast.actorNamed( + "Faber", + CallAnApi.at(config.verifier.url.toExternalForm()), + ListenToEvents.at(config.verifier.webhookUrl!!) + ) + OnStage.setTheStage(cast) + + // Create issuer wallet and tenant + val createIssuerWalletResponse = RestAssured + .given().body( + CreateWalletRequest( + name = "IssuerWallet", + seed = Random.nextBytes(64).toHexString(), + id = UUID.randomUUID() + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.issuer.url}/wallets") + .thenReturn() + Ensure.that(createIssuerWalletResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + val issuerWallet = createIssuerWalletResponse.body.jsonPath().getObject("", WalletDetail::class.java) + + val issuerTenantResponse = RestAssured + .given().body( + CreateEntityRequest( + name = "Issuer", + walletId = issuerWallet.id + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.issuer.url}/iam/entities") + .thenReturn() + Ensure.that(issuerTenantResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + val issuerEntity = issuerTenantResponse.body.jsonPath().getObject("", EntityResponse::class.java) + + val issuerAddApiKeyResponse = + RestAssured + .given().body( + ApiKeyAuthenticationRequest( + entityId = issuerEntity.id, + apiKey = config.issuer.apikey!! + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.issuer.url}/iam/apikey-authentication") + .thenReturn() + Ensure.that(issuerAddApiKeyResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + + // Create verifier wallet + val createVerifierWalletResponse = RestAssured + .given().body( + CreateWalletRequest( + name = "VerifierWallet", + seed = Random.nextBytes(64).toHexString(), + id = UUID.randomUUID() + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.verifier.url}/wallets") + .thenReturn() + Ensure.that(createVerifierWalletResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + val verifierWallet = createVerifierWalletResponse.body.jsonPath().getObject("", WalletDetail::class.java) + // Create verifier tenant + val verifierTenantResponse = RestAssured + .given().body( + CreateEntityRequest( + name = "Verifier", + walletId = verifierWallet.id + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.verifier.url}/iam/entities") + .thenReturn() + Ensure.that(verifierTenantResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + val verifierEntity = verifierTenantResponse.body.jsonPath().getObject("", EntityResponse::class.java) + // Add verifier api key + val verifierAddApiKeyResponse = + RestAssured + .given().body( + ApiKeyAuthenticationRequest( + entityId = verifierEntity.id, + apiKey = config.verifier.apikey!! + ) + ) + .header(config.global.adminAuthHeader, config.admin.apikey) + .post("${config.verifier.url}/iam/apikey-authentication") + .thenReturn() + Ensure.that(verifierAddApiKeyResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + + cast.actors.forEach { actor -> + when (actor.name) { + "Acme" -> { + actor.remember("AUTH_KEY", config.issuer.apikey) + } + "Bob" -> { + actor.remember("AUTH_KEY", config.holder.apikey) + } + "Faber" -> { + actor.remember("AUTH_KEY", config.verifier.apikey) + } + } + } + + val registerIssuerWebhookResponse = + RestAssured + .given().body( + CreateWebhookNotification( + url = config.issuer.webhookUrl.toExternalForm() + ) + ) + .header(config.global.authHeader, config.issuer.apikey) + .post("${config.issuer.url}/events/webhooks") + .thenReturn() + Ensure.that(registerIssuerWebhookResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) + + val registerVerifierWebhookResponse = + RestAssured + .given().body( + CreateWebhookNotification( + url = config.verifier.webhookUrl.toExternalForm() + ) + ) + .header(config.global.authHeader, config.verifier.apikey) + .post("${config.verifier.url}/events/webhooks") + .thenReturn() + Ensure.that(registerVerifierWebhookResponse.statusCode).isEqualTo(HttpStatus.SC_CREATED) +} + +@AfterAll +fun clearStage() { + OnStage.drawTheCurtain() +} + +class CommonSteps { + @ParameterType(".*") + fun actor(actorName: String): Actor { + return OnStage.theActorCalled(actorName) + } + + @Given("{actor} has an issued credential from {actor}") + fun holderHasIssuedCredentialFromIssuer(holder: Actor, issuer: Actor) { + holder.attemptsTo( + Get.resource("/issue-credentials/records") + ) + holder.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + val receivedCredential = SerenityRest.lastResponse().get().contents!!.findLast { credential -> + credential.protocolState == IssueCredentialRecord.ProtocolState.credentialReceived + } + + if (receivedCredential != null) { + holder.remember("issuedCredential", receivedCredential) + } else { + val publishDidSteps = PublishDidSteps() + val issueSteps = IssueCredentialsSteps() + actorsHaveExistingConnection(issuer, holder) + publishDidSteps.createsUnpublishedDid(holder) + publishDidSteps.createsUnpublishedDid(issuer) + publishDidSteps.hePublishesDidToLedger(issuer) + issueSteps.acmeOffersACredential(issuer, holder, "short") + issueSteps.bobRequestsTheCredential(holder) + issueSteps.acmeIssuesTheCredential(issuer) + issueSteps.bobHasTheCredentialIssued(holder) + } + } + + @Given("{actor} and {actor} have an existing connection") + fun actorsHaveExistingConnection(inviter: Actor, invitee: Actor) { + inviter.attemptsTo( + Get.resource("/connections") + ) + inviter.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + val inviterConnection = SerenityRest.lastResponse().get().contents!!.firstOrNull { + it.label == "Connection with ${invitee.name}" && it.state == Connection.State.connectionResponseSent + } + + var inviteeConnection: Connection? = null + if (inviterConnection != null) { + invitee.attemptsTo( + Get.resource("/connections") + ) + invitee.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + inviteeConnection = SerenityRest.lastResponse().get().contents!!.firstOrNull { + it.theirDid == inviterConnection.myDid && it.state == Connection.State.connectionResponseReceived + } + } + + if (inviterConnection != null && inviteeConnection != null) { + inviter.remember("connection-with-${invitee.name}", inviterConnection) + invitee.remember("connection-with-${inviter.name}", inviteeConnection) + } else { + val connectionSteps = ConnectionSteps() + connectionSteps.inviterGeneratesAConnectionInvitation(inviter, invitee) + connectionSteps.inviteeSendsAConnectionRequestToInviter(invitee, inviter) + connectionSteps.inviterReceivesTheConnectionRequest(inviter) + connectionSteps.inviteeReceivesTheConnectionResponse(invitee) + connectionSteps.inviterAndInviteeHaveAConnection(inviter, invitee) + } + } +} diff --git a/tests/integration-tests/src/test/kotlin/features/connection/ConnectionSteps.kt b/tests/integration-tests/src/test/kotlin/features/connection/ConnectionSteps.kt new file mode 100644 index 0000000000..7724e32773 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/connection/ConnectionSteps.kt @@ -0,0 +1,135 @@ +package features.connection + +import common.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.prism.models.AcceptConnectionInvitationRequest +import io.iohk.atala.prism.models.Connection +import io.iohk.atala.prism.models.CreateConnectionRequest +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 + +class ConnectionSteps { + + @When("{actor} generates a connection invitation to {actor}") + fun inviterGeneratesAConnectionInvitation(inviter: Actor, invitee: Actor) { + // Acme(Issuer) initiates a connection + // and sends it to Bob(Holder) out-of-band, e.g. using QR-code + val connectionLabel = "Connection with ${invitee.name}" + inviter.attemptsTo( + Post.to("/connections") + .with { + it.body( + CreateConnectionRequest(label = connectionLabel) + ) + } + ) + + val connection = SerenityRest.lastResponse().get() + + inviter.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + Ensure.that(connection.label!!).isEqualTo(connectionLabel), + Ensure.that(connection.state).isEqualTo(Connection.State.invitationGenerated), + Ensure.that(connection.role).isEqualTo(Connection.Role.inviter) + ) + + // Acme remembers connection to send it out of band to Bob + inviter.remember("connection", connection) + } + + @When("{actor} sends a connection request to {actor}") + fun inviteeSendsAConnectionRequestToInviter(invitee: Actor, inviter: Actor) { + // Bob accepts connection using achieved out-of-band invitation + val inviterConnection = inviter.recall("connection") + invitee.attemptsTo( + Post.to("/connection-invitations") + .with { + it.body( + AcceptConnectionInvitationRequest( + inviterConnection.invitation.invitationUrl.split("=")[1] + ) + ) + } + ) + val inviteeConnection = SerenityRest.lastResponse().get() + + invitee.attemptsTo( + 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.type).isEqualTo(inviterConnection.invitation.type), + Ensure.that(inviteeConnection.state).isEqualTo(Connection.State.connectionRequestPending), + Ensure.that(inviteeConnection.role).isEqualTo(Connection.Role.invitee) + ) + + invitee.remember("connection", inviteeConnection) + } + + @When("{actor} receives the connection request and sends back the response") + fun inviterReceivesTheConnectionRequest(inviter: Actor) { + wait( + { + val lastEvent = ListenToEvents.`as`(inviter).connectionEvents.lastOrNull { + it.data.thid == inviter.recall("connection").thid + } + lastEvent != null && + lastEvent.data.state == Connection.State.connectionResponseSent + }, + "Inviter connection didn't reach ${Connection.State.connectionResponseSent} state" + ) + } + + @When("{actor} receives the connection response") + fun inviteeReceivesTheConnectionResponse(invitee: Actor) { + // Bob (Holder) receives final connection response + wait( + { + val lastEvent = ListenToEvents.`as`(invitee).connectionEvents.lastOrNull { + it.data.thid == invitee.recall("connection").thid + } + lastEvent != null && + lastEvent.data.state == Connection.State.connectionResponseReceived + }, + "Invitee connection didn't reach ${Connection.State.connectionResponseReceived} state." + ) + } + + @Then("{actor} and {actor} have a connection") + fun inviterAndInviteeHaveAConnection(inviter: Actor, invitee: Actor) { + // Connection established. Both parties exchanged their DIDs with each other + inviter.attemptsTo( + Get.resource("/connections/${inviter.recall("connection").connectionId}") + ) + inviter.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + inviter.remember("connection-with-${invitee.name}", SerenityRest.lastResponse().get()) + + invitee.attemptsTo( + Get.resource("/connections/${invitee.recall("connection").connectionId}") + ) + invitee.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + invitee.remember("connection-with-${inviter.name}", SerenityRest.lastResponse().get()) + + assertThat(inviter.recall("connection-with-${invitee.name}").myDid) + .isEqualTo(invitee.recall("connection-with-${inviter.name}").theirDid) + assertThat(inviter.recall("connection-with-${invitee.name}").theirDid) + .isEqualTo(invitee.recall("connection-with-${inviter.name}").myDid) + assertThat(inviter.recall("connection-with-${invitee.name}").state) + .isEqualTo(Connection.State.connectionResponseSent) + assertThat(invitee.recall("connection-with-${inviter.name}").state) + .isEqualTo(Connection.State.connectionResponseReceived) + } +} diff --git a/tests/e2e-tests/src/test/kotlin/features/issue_credentials/IssueCredentialsSteps.kt b/tests/integration-tests/src/test/kotlin/features/credentials/IssueCredentialsSteps.kt similarity index 59% rename from tests/e2e-tests/src/test/kotlin/features/issue_credentials/IssueCredentialsSteps.kt rename to tests/integration-tests/src/test/kotlin/features/credentials/IssueCredentialsSteps.kt index f57355234c..f413cad45c 100644 --- a/tests/e2e-tests/src/test/kotlin/features/issue_credentials/IssueCredentialsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/credentials/IssueCredentialsSteps.kt @@ -1,14 +1,19 @@ -package features.issue_credentials +package features.credentials -import api_models.* import common.ListenToEvents -import common.Utils.lastResponseObject 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 io.iohk.atala.prism.models.AcceptCredentialOfferRequest +import io.iohk.atala.prism.models.Connection +import io.iohk.atala.prism.models.CreateIssueCredentialRecordRequest +import io.iohk.atala.prism.models.IssueCredentialRecord +import models.CredentialEvent +import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence import org.apache.http.HttpStatus.SC_CREATED import org.apache.http.HttpStatus.SC_OK @@ -18,35 +23,39 @@ class IssueCredentialsSteps { @When("{actor} offers a credential to {actor} with {string} form DID") fun acmeOffersACredential(issuer: Actor, holder: Actor, didForm: String) { + val did: String = if (didForm == "short") { + issuer.recall("shortFormDid") + } else { + issuer.recall("longFormDid") + } - val did: String = if (didForm == "short") - issuer.recall("shortFormDid") else issuer.recall("longFormDid") - - val newCredential = Credential( + val credentialOfferRequest = CreateIssueCredentialRecordRequest( schemaId = null, - validityPeriod = 3600.0, - automaticIssuance = false, - awaitConfirmation = false, claims = linkedMapOf( "firstName" to "FirstName", - "lastName" to "LastName", + "lastName" to "LastName" ), issuingDID = did, - connectionId = issuer.recall("connection-with-${holder.name}").connectionId, + connectionId = issuer.recall("connection-with-${holder.name}").connectionId.toString(), + validityPeriod = 3600.0, + automaticIssuance = false ) + issuer.attemptsTo( Post.to("/issue-credentials/credential-offers") .with { - it.body(newCredential) - }, + it.body(credentialOfferRequest) + } ) - issuer.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_CREATED) - }, + + val credentialRecord = SerenityRest.lastResponse().get() + + issuer.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) - issuer.remember("thid", lastResponseObject("", Credential::class).thid) - holder.remember("thid", lastResponseObject("", Credential::class).thid) + + issuer.remember("thid", credentialRecord.thid) + holder.remember("thid", credentialRecord.thid) } @When("{actor} receives the credential offer and accepts") @@ -57,9 +66,9 @@ class IssueCredentialsSteps { it.data.thid == holder.recall("thid") } credentialEvent != null && - credentialEvent!!.data.protocolState == CredentialState.OFFER_RECEIVED + credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.offerReceived }, - "Holder was unable to receive the credential offer from Issuer! Protocol state did not achieve OfferReceived state.", + "Holder was unable to receive the credential offer from Issuer! Protocol state did not achieve OfferReceived state." ) val recordId = ListenToEvents.`as`(holder).credentialEvents.last().data.recordId @@ -68,15 +77,13 @@ class IssueCredentialsSteps { holder.attemptsTo( Post.to("/issue-credentials/records/$recordId/accept-offer") .with { - it.body(""" - { "subjectId": "${holder.recall("longFormDid")}" } - """.trimIndent()) - }, + it.body( + AcceptCredentialOfferRequest(holder.recall("longFormDid")) + ) + } ) - holder.should( - ResponseConsequence.seeThatResponse("Accept offer") { - it.statusCode(SC_OK) - }, + holder.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) ) } @@ -88,18 +95,16 @@ class IssueCredentialsSteps { it.data.thid == issuer.recall("thid") } credentialEvent != null && - credentialEvent!!.data.protocolState == CredentialState.REQUEST_RECEIVED + credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.requestReceived }, - "Issuer was unable to receive the credential request from Holder! Protocol state did not achieve RequestReceived state.", + "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"), + Post.to("/issue-credentials/records/$recordId/issue-credential") ) - issuer.should( - ResponseConsequence.seeThatResponse("Issue credential") { - it.statusCode(SC_OK) - }, + issuer.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) ) wait( @@ -108,10 +113,10 @@ class IssueCredentialsSteps { it.data.thid == issuer.recall("thid") } credentialEvent != null && - credentialEvent!!.data.protocolState == CredentialState.CREDENTIAL_SENT + credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.credentialSent }, "Issuer was unable to issue the credential! " + - "Protocol state did not achieve ${CredentialState.CREDENTIAL_SENT} state.", + "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.credentialSent} state." ) } @@ -123,10 +128,10 @@ class IssueCredentialsSteps { it.data.thid == holder.recall("thid") } credentialEvent != null && - credentialEvent!!.data.protocolState == CredentialState.CREDENTIAL_RECEIVED + credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.credentialReceived }, "Holder was unable to receive the credential from Issuer! " + - "Protocol state did not achieve ${CredentialState.CREDENTIAL_RECEIVED} state.", + "Protocol state did not achieve ${IssueCredentialRecord.ProtocolState.credentialReceived} state." ) holder.remember("issuedCredential", ListenToEvents.`as`(holder).credentialEvents.last().data) } diff --git a/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt b/tests/integration-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt similarity index 55% rename from tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt rename to tests/integration-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt index d5c56a029f..29e7a7434e 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/did/DeactivateDidSteps.kt @@ -1,31 +1,33 @@ package features.did -import common.ListenToEvents import common.TestConstants -import common.Utils.lastResponseObject 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.prism.models.DIDOperationResponse +import io.iohk.atala.prism.models.DIDResolutionResult +import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import interactions.Get -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence import org.apache.http.HttpStatus -import org.hamcrest.Matchers class DeactivateDidSteps { @When("{actor} deactivates PRISM DID") fun actorIssuesDeactivateDidOperation(actor: Actor) { actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/deactivations"), + Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/deactivations") ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(HttpStatus.SC_ACCEPTED) - it.body("scheduledOperation.didRef", Matchers.not(Matchers.emptyString())) - it.body("scheduledOperation.id", Matchers.not(Matchers.emptyString())) - }, + + val didOperationResponse = SerenityRest.lastResponse().get() + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), + Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), + Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty() ) } @@ -34,12 +36,12 @@ class DeactivateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - lastResponseObject("didDocumentMetadata.deactivated", String::class) == "true" + SerenityRest.lastResponse().get().didDocumentMetadata.deactivated!! }, "ERROR: DID deactivate operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } } diff --git a/tests/e2e-tests/src/test/kotlin/features/did/ManageDidSteps.kt b/tests/integration-tests/src/test/kotlin/features/did/ManageDidSteps.kt similarity index 60% rename from tests/e2e-tests/src/test/kotlin/features/did/ManageDidSteps.kt rename to tests/integration-tests/src/test/kotlin/features/did/ManageDidSteps.kt index 84fd532c8c..d3cd209298 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/ManageDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/did/ManageDidSteps.kt @@ -1,22 +1,17 @@ package features.did -import api_models.* -import common.Ensure -import common.TestConstants -import common.Utils.lastResponseList -import common.Utils.lastResponseObject -import common.Utils.toJsonPath +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 net.serenitybdd.rest.SerenityRest.lastResponse +import io.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.extensions.toJsonPath +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.* +import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import interactions.Get -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence import org.apache.http.HttpStatus.SC_CREATED -import org.assertj.core.api.Assertions -import org.hamcrest.Matchers.* class ManageDidSteps { @@ -36,79 +31,87 @@ class ManageDidSteps { Post.to("/did-registrar/dids") .with { it.body(createDidRequest) - }, + } ) + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) + ) + var createdDids = actor.recall>("createdDids") if (createdDids == null) { createdDids = mutableListOf() } - createdDids.add(lastResponseObject("longFormDid", String::class)) + + val managedDid = SerenityRest.lastResponse().get() + + createdDids.add(managedDid.longFormDid!!) actor.remember("createdDids", createdDids) } @When("{actor} tries to create PRISM DID with missing {word}") fun triesToCreateManagedDidWithMissingField(actor: Actor, missingFieldPath: String) { val createDidRequest = createPrismDidRequest() - val requestBody = toJsonPath(createDidRequest).delete(missingFieldPath).jsonString() + val requestBody = createDidRequest.toJsonPath().delete(missingFieldPath).jsonString() actor.attemptsTo( Post.to("/did-registrar/dids") .with { it.body(requestBody) - }, + } ) } @When("{actor} tries to create a managed DID with value {word} in {word}") fun trisToCreateManagedDidWithValueInField(actor: Actor, value: String, fieldPath: String) { val createDidRequest = createPrismDidRequest() - val requestBody = toJsonPath(createDidRequest).set(fieldPath, value).jsonString() + val requestBody = createDidRequest.toJsonPath().set(fieldPath, value).jsonString() actor.attemptsTo( Post.to("/did-registrar/dids") .with { it.body(requestBody) - }, + } ) } @When("{actor} lists all PRISM DIDs") fun iListManagedDids(actor: Actor) { actor.attemptsTo( - Get.resource("/did-registrar/dids"), + Get.resource("/did-registrar/dids") ) } @Then("{actor} sees PRISM DID was created successfully") fun theDidShouldBeRegisteredSuccessfully(actor: Actor) { - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(SC_CREATED) - it.body("longFormDid", not(emptyString())) - }, + val managedDid = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + Ensure.that(managedDid.longFormDid!!).isNotEmpty() ) } @Then("{actor} sees the request has failed with error status {int}") fun seesTheRequestHasFailedWithErrorStatus(actor: Actor, errorStatusCode: Int) { - Assertions.assertThat(lastResponse().statusCode).isEqualTo(errorStatusCode) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(errorStatusCode) + ) } @Then("{actor} sees the list contains all created DIDs") fun seeTheListContainsAllCreatedDids(actor: Actor) { val expectedDids = actor.recall>("createdDids") - val managedDidList = lastResponseList("contents.longFormDid", String::class) + val managedDidList = SerenityRest.lastResponse().get().contents!! + .filter { it.status == "CREATED" }.map { it.longFormDid!! } actor.attemptsTo( Ensure.that(managedDidList).containsElementsFrom(expectedDids) ) } - private fun createPrismDidRequest(): CreatePrismDidRequest { - val publicKeys = listOf( - TestConstants.PRISM_DID_AUTH_KEY, - ) - val services = listOf( - TestConstants.PRISM_DID_SERVICE, + private fun createPrismDidRequest(): CreateManagedDidRequest = CreateManagedDidRequest( + CreateManagedDidRequestDocumentTemplate( + publicKeys = listOf(ManagedDIDKeyTemplate("auth-1", Purpose.authentication)), + services = listOf( + Service("https://foo.bar.com", listOf("LinkedDomains"), Json("https://foo.bar.com/")) + ) ) - val documentTemplate = DocumentTemplate(publicKeys, services) - return CreatePrismDidRequest(documentTemplate) - } + ) } diff --git a/tests/integration-tests/src/test/kotlin/features/did/PublishDidSteps.kt b/tests/integration-tests/src/test/kotlin/features/did/PublishDidSteps.kt new file mode 100644 index 0000000000..45f1c12217 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/did/PublishDidSteps.kt @@ -0,0 +1,140 @@ +package features.did + +import common.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.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.* +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 + +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( + CreateManagedDidRequestDocumentTemplate( + publicKeys = listOf( + ManagedDIDKeyTemplate("auth-1", Purpose.authentication), + ManagedDIDKeyTemplate("assertion-1", Purpose.assertionMethod) + ), + services = listOf( + Service("https://foo.bar.com", listOf("LinkedDomains"), Json("https://foo.bar.com/")), + Service("https://update.com", listOf("LinkedDomains"), Json("https://update.com/")), + Service("https://remove.com", listOf("LinkedDomains"), Json("https://remove.com/")) + ) + ) + ) + actor.attemptsTo( + Post.to("/did-registrar/dids") + .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) + + actor.attemptsTo( + 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 + ) + } + + @When("{actor} publishes DID to ledger") + fun hePublishesDidToLedger(actor: Actor) { + actor.attemptsTo( + Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/publications") + ) + val didOperationResponse = SerenityRest.lastResponse().get() + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), + Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), + Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty() + ) + + wait( + { + val didEvent = + ListenToEvents.`as`(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 + ) + actor.attemptsTo( + Get.resource("/dids/${actor.recall("shortFormDid")}") + ) + + val didDocument = SerenityRest.lastResponse().get().didDocument!! + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK), + Ensure.that(didDocument.id).isEqualTo(actor.recall("shortFormDid")) + ) + } + + @Then("{actor} resolves DID document corresponds to W3C standard") + fun heSeesDidDocumentCorrespondsToW3cStandard(actor: Actor) { + val didResolutionResult = SerenityRest.lastResponse().get() + val didDocument = didResolutionResult.didDocument!! + val shortFormDid = actor.recall("shortFormDid") + actor.attemptsTo( + Ensure.that(didDocument.id).isEqualTo(shortFormDid), + Ensure.that(didDocument.authentication!![0]) + .isEqualTo("$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}"), + Ensure.that(didDocument.verificationMethod!![0].controller).isEqualTo(shortFormDid), + Ensure.that(didResolutionResult.didDocumentMetadata.deactivated!!).isFalse() + ) + } +} diff --git a/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt b/tests/integration-tests/src/test/kotlin/features/did/UpdateDidSteps.kt similarity index 63% rename from tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt rename to tests/integration-tests/src/test/kotlin/features/did/UpdateDidSteps.kt index 3d566291de..51044b3b93 100644 --- a/tests/e2e-tests/src/test/kotlin/features/did/UpdateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/did/UpdateDidSteps.kt @@ -1,69 +1,72 @@ package features.did -import api_models.* import common.TestConstants -import common.Utils.lastResponseList 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.prism.models.* +import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import interactions.Get -import interactions.Post -import net.serenitybdd.screenplay.rest.questions.ResponseConsequence import org.apache.http.HttpStatus -import org.hamcrest.Matchers.emptyString -import org.hamcrest.Matchers.not class UpdateDidSteps { @When("{actor} updates PRISM DID by adding new keys") fun actorUpdatesPrismDidByAddingNewKeys(actor: Actor) { - val updatePrismDidAction = UpdatePrismDidAction( - actionType = "ADD_KEY", - addKey = TestConstants.PRISM_DID_UPDATE_NEW_AUTH_KEY, + val updatePrismDidAction = UpdateManagedDIDRequestAction( + actionType = ActionType.aDDKEY, + ManagedDIDKeyTemplate("auth-2", Purpose.authentication) ) actor.remember("updatePrismDidAction", updatePrismDidAction) } @When("{actor} updates PRISM DID by removing keys") fun actorUpdatesPrismDidByRemovingKeys(actor: Actor) { - val updatePrismDidAction = UpdatePrismDidAction( - actionType = "REMOVE_KEY", - removeKey = TestConstants.PRISM_DID_AUTH_KEY, + val updatePrismDidAction = UpdateManagedDIDRequestAction( + actionType = ActionType.rEMOVEKEY, + removeKey = RemoveEntryById("auth-1") ) actor.remember("updatePrismDidAction", updatePrismDidAction) } @When("{actor} updates PRISM DID with new services") fun actorUpdatesPrismDidWithNewServices(actor: Actor) { - val updatePrismDidAction = UpdatePrismDidAction( - actionType = "ADD_SERVICE", - addService = TestConstants.PRISM_DID_UPDATE_NEW_SERVICE, + val updatePrismDidAction = UpdateManagedDIDRequestAction( + actionType = ActionType.aDDSERVICE, + addService = Service( + "https://new.service.com", + listOf("LinkedDomains"), + Json("https://new.service.com/") + ) ) actor.remember("updatePrismDidAction", updatePrismDidAction) } @When("{actor} updates PRISM DID by removing services") fun actorUpdatesPrismDidByRemovingServices(actor: Actor) { - val updatePrismDidAction = UpdatePrismDidAction( - actionType = "REMOVE_SERVICE", - removeService = TestConstants.PRISM_DID_UPDATE_NEW_SERVICE, + val updatePrismDidAction = UpdateManagedDIDRequestAction( + actionType = ActionType.rEMOVESERVICE, + removeService = RemoveEntryById("https://new.service.com") ) actor.remember("updatePrismDidAction", updatePrismDidAction) } @When("{actor} updates PRISM DID by updating services") fun actorUpdatesPrismDidByUpdatingServices(actor: Actor) { - val newService = Service( + val newService = UpdateManagedDIDServiceAction( id = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.id, type = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.type, - serviceEndpoint = listOf( - TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL, - ), + serviceEndpoint = Json( + TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL + ) ) - val updatePrismDidAction = UpdatePrismDidAction( - actionType = "UPDATE_SERVICE", - updateService = newService, + val updatePrismDidAction = UpdateManagedDIDRequestAction( + actionType = ActionType.uPDATESERVICE, + updateService = newService ) actor.remember("updatePrismDidAction", updatePrismDidAction) } @@ -73,15 +76,14 @@ class UpdateDidSteps { actor.attemptsTo( Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/updates") .with { - it.body(UpdatePrismDidRequest(listOf(actor.recall("updatePrismDidAction")))) - }, + it.body(UpdateManagedDIDRequest(listOf(actor.recall("updatePrismDidAction")))) + } ) - actor.should( - ResponseConsequence.seeThatResponse { - it.statusCode(HttpStatus.SC_ACCEPTED) - it.body("scheduledOperation.didRef", not(emptyString())) - it.body("scheduledOperation.id", not(emptyString())) - }, + val didOperationResponse = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), + Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), + Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty() ) } @@ -90,10 +92,10 @@ class UpdateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - val authUris = lastResponseList("didDocument.authentication", String::class) - val verificationMethods = lastResponseList("didDocument.verificationMethod.id", String::class) + 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 { @@ -101,7 +103,7 @@ class UpdateDidSteps { } }, "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } @@ -110,10 +112,10 @@ class UpdateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - val authUris = lastResponseList("didDocument.authentication", String::class) - val verificationMethods = lastResponseList("didDocument.verificationMethod.id", String::class) + 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 { @@ -121,7 +123,7 @@ class UpdateDidSteps { } }, "ERROR: DID UPDATE operation did not succeed on the ledger!", - timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } @@ -130,15 +132,15 @@ class UpdateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - val serviceIds = lastResponseList("didDocument.service.id", String::class) + 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, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } @@ -147,15 +149,15 @@ class UpdateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - val serviceIds = lastResponseList("didDocument.service.id", String::class) + 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, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } @@ -164,13 +166,13 @@ class UpdateDidSteps { wait( { actor.attemptsTo( - Get.resource("/dids/${actor.recall("shortFormDid")}"), + Get.resource("/dids/${actor.recall("shortFormDid")}") ) - val service = lastResponseList("didDocument.service", Service::class) - service.any { it.serviceEndpoint.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } + 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, + timeout = TestConstants.DID_UPDATE_PUBLISH_MAX_WAIT_5_MIN ) } } diff --git a/tests/e2e-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt b/tests/integration-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt similarity index 53% rename from tests/e2e-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt rename to tests/integration-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt index 3e45e7d4f3..4a0c88e297 100644 --- a/tests/e2e-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/multitenancy/EntitySteps.kt @@ -1,10 +1,11 @@ package features.multitenancy -import api_models.CreateEntityRequest -import api_models.AddApiKeyRequest -import common.Ensure -import common.Utils import interactions.Post +import io.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.ApiKeyAuthenticationRequest +import io.iohk.atala.prism.models.CreateEntityRequest +import io.iohk.atala.prism.models.EntityResponse import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.SC_CREATED @@ -14,9 +15,10 @@ class EntitySteps { fun createNewEntity( actor: Actor, - walletId: String, + walletId: UUID, name: String = "", - id: String = UUID.randomUUID().toString()): String { + id: UUID = UUID.randomUUID() + ): EntityResponse { actor.attemptsTo( Post.to("/iam/entities") .with { @@ -24,31 +26,31 @@ class EntitySteps { CreateEntityRequest( walletId = walletId, name = name, - id = id, + id = id ) ) - }, + } ) actor.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) - return Utils.lastResponseObject("id", String::class) + return SerenityRest.lastResponse().get() } - fun addNewApiKeyToEntity(actor: Actor, entityId: String, apiKey: String) { + fun addNewApiKeyToEntity(actor: Actor, entityId: UUID, apiKey: String) { actor.attemptsTo( Post.to("/iam/apikey-authentication") .with { it.body( - AddApiKeyRequest( + ApiKeyAuthenticationRequest( entityId = entityId, - apiKey = apiKey, + apiKey = apiKey ) ) - }, + } ) actor.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) } } diff --git a/tests/integration-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt b/tests/integration-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt new file mode 100644 index 0000000000..0348674dc4 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/multitenancy/EventsSteps.kt @@ -0,0 +1,24 @@ +package features.multitenancy + +import interactions.Post +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.CreateWebhookNotification +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus + +class EventsSteps { + fun registerNewWebhook(actor: Actor, webhookUrl: String) { + actor.attemptsTo( + Post.to("/events/webhooks") + .with { + it.body( + CreateWebhookNotification(url = webhookUrl) + ) + } + ) + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_CREATED) + ) + } +} diff --git a/tests/e2e-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt b/tests/integration-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt similarity index 58% rename from tests/e2e-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt rename to tests/integration-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt index b6815edb9e..d3f3d47d71 100644 --- a/tests/e2e-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/features/multitenancy/WalletsSteps.kt @@ -1,21 +1,22 @@ package features.multitenancy -import api_models.CreateWalletRequest -import common.Ensure import common.TestConstants -import common.Utils 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.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.serenity.ensure.Ensure +import io.iohk.atala.prism.models.CreateWalletRequest +import io.iohk.atala.prism.models.WalletDetail +import io.iohk.atala.prism.models.WalletDetailPage import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor import org.apache.http.HttpStatus.* import java.util.* import kotlin.random.Random - class WalletsSteps { @OptIn(ExperimentalStdlibApi::class) @@ -23,7 +24,8 @@ class WalletsSteps { actor: Actor, name: String = "test-wallet", seed: String = Random.nextBytes(64).toHexString(), - id: String = UUID.randomUUID().toString()) { + id: UUID = UUID.randomUUID() + ): WalletDetail { actor.attemptsTo( Post.to("/wallets") .with { @@ -31,33 +33,32 @@ class WalletsSteps { CreateWalletRequest( name = name, seed = seed, - id = id, + id = id ) ) - }, + } ) + return SerenityRest.lastResponse().get() } @When("{actor} creates new wallet with name {string}") fun iCreateNewWalletWithName(acme: Actor, name: String) { - createNewWallet(acme, name) + val wallet = createNewWallet(acme, name) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) - acme.remember("walletId", Utils.lastResponseObject("id", String::class)) + acme.remember("walletId", wallet.id) } @When("{actor} creates new wallet with unique id") fun acmeCreateNewWalletWithId(acme: Actor) { - val uniqueId = UUID.randomUUID().toString() + val uniqueId = UUID.randomUUID() acme.remember("uniqueId", uniqueId) - createNewWallet(acme, id = uniqueId) + val wallet = createNewWallet(acme, id = uniqueId) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) - .withReportedError("Response status code is not correct!"), - Ensure.that(Utils.lastResponseObject("id", String::class)).isEqualTo(uniqueId) - .withReportedError("Wallet id is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + Ensure.that(wallet.id).isEqualTo(uniqueId) + .withReportedError("Wallet id is not correct!") ) } @@ -65,8 +66,7 @@ class WalletsSteps { fun acmeCreateNewWalletWithTheSameId(acme: Actor) { createNewWallet(acme, id = acme.recall("uniqueId")) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_BAD_REQUEST) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_BAD_REQUEST) ) } @@ -76,8 +76,7 @@ class WalletsSteps { acme.remember("uniqueName", name) createNewWallet(acme, name = name) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) } @@ -85,8 +84,7 @@ class WalletsSteps { fun acmeCreatesNewWalletWithTheSameUniqueName(acme: Actor) { createNewWallet(acme, name = acme.recall("uniqueName")) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_CREATED) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) ) } @@ -96,13 +94,15 @@ class WalletsSteps { Get.resource("/wallets/${acme.recall("walletId")}") .with { it.queryParam("name", name) - }, + } ) + val wallet = SerenityRest.lastResponse().get() + acme.attemptsTo( - Ensure.that(Utils.lastResponseObject("name", String::class)).isEqualTo(name) + Ensure.that(wallet.name).isEqualTo(name) .withReportedError("Wallet name is not correct!"), - Ensure.that(Utils.lastResponseObject("id", String::class)).isEqualTo(acme.recall("walletId")) - .withReportedError("Wallet id is not correct!"), + Ensure.that(wallet.id).isEqualTo(acme.recall("walletId")) + .withReportedError("Wallet id is not correct!") ) } @@ -112,33 +112,30 @@ class WalletsSteps { Get.resource("/wallets") ) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_OK) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) ) - val wallets = Utils.lastResponseList("contents.name", String::class).filter { it == acme.recall("uniqueName") } + val wallets = SerenityRest.lastResponse().get().contents!!.filter { it.name == acme.recall("uniqueName") } acme.attemptsTo( Ensure.that(wallets.size).isEqualTo(2) - .withReportedError("Two wallets with the same name were not created!"), + .withReportedError("Two wallets with the same name were not created!") ) } @Then("{actor} should have only one wallet and second operation should fail") fun acmeShouldHaveOnlyOneWalletAndSecondOperationShouldFail(acme: Actor) { acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_BAD_REQUEST) - .withReportedError("Response status code is not correct!") + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_BAD_REQUEST) ) acme.attemptsTo( Get.resource("/wallets") ) acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_OK) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) ) - val wallets = Utils.lastResponseList("contents.id", String::class).filter { it == acme.recall("uniqueId") } + val wallets = SerenityRest.lastResponse().get().contents!!.filter { it.id == acme.recall("uniqueId") } acme.attemptsTo( Ensure.that(wallets.size).isEqualTo(1) - .withReportedError("Only one wallet should be created with the same id!"), + .withReportedError("Only one wallet should be created with the same id!") ) } @@ -150,8 +147,7 @@ class WalletsSteps { @Then("{actor} should see the error and wallet should not be created") fun acmeShouldSeeTheErrorAndWalletShouldNotBeCreated(acme: Actor) { acme.attemptsTo( - Ensure.that(SerenityRest.lastResponse().statusCode).isEqualTo(SC_BAD_REQUEST) - .withReportedError("Response status code is not correct!"), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_BAD_REQUEST) ) } } diff --git a/tests/integration-tests/src/test/kotlin/features/proofs/PresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/features/proofs/PresentProofSteps.kt new file mode 100644 index 0000000000..4793da20ec --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/proofs/PresentProofSteps.kt @@ -0,0 +1,124 @@ +package features.proofs + +import common.ListenToEvents +import common.Utils.wait +import interactions.Patch +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.prism.models.* +import models.PresentationEvent +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus.SC_CREATED + +class PresentProofSteps { + + private var proofEvent: PresentationEvent? = null + + @When("{actor} sends a request for proof presentation to {actor}") + fun faberSendsARequestForProofPresentationToBob(faber: Actor, bob: Actor) { + val presentationRequest = RequestPresentationInput( + connectionId = faber.recall("connection-with-${bob.name}").connectionId.toString(), + options = Options( + challenge = "11c91493-01b3-4c4d-ac36-b336bab5bddf", + domain = "https://example-verifier.com" + ), + proofs = listOf( + ProofRequestAux( + schemaId = "https://schema.org/Person", + trustIssuers = listOf("did:web:atalaprism.io/users/testUser") + ) + ) + ) + faber.attemptsTo( + Post.to("/present-proof/presentations") + .with { + it.body( + presentationRequest + ) + } + ) + faber.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) + ) + val presentationStatus = SerenityRest.lastResponse().get() + faber.remember("thid", presentationStatus.thid) + bob.remember("thid", presentationStatus.thid) + } + + @When("{actor} receives the request") + fun bobReceivesTheRequest(bob: Actor) { + wait( + { + proofEvent = ListenToEvents.`as`(bob).presentationEvents.lastOrNull { + it.data.thid == bob.recall("thid") + } + proofEvent != null && + proofEvent!!.data.status == PresentationStatus.Status.requestReceived + }, + "ERROR: Bob did not achieve any presentation request!" + ) + bob.remember("presentationId", proofEvent!!.data.presentationId) + } + + @When("{actor} makes the presentation of the proof to {actor}") + fun bobMakesThePresentationOfTheProof(bob: Actor, faber: Actor) { + val requestPresentationAction = RequestPresentationAction( + proofId = listOf(bob.recall("issuedCredential").recordId), + action = RequestPresentationAction.Action.requestMinusAccept + ) + + bob.attemptsTo( + Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { + it.body( + requestPresentationAction + ) + } + ) + } + + @When("{actor} rejects the proof") + fun bobRejectsProof(bob: Actor) { + bob.attemptsTo( + Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { + it.body( + RequestPresentationAction( + action = RequestPresentationAction.Action.requestMinusReject + ) + ) + } + ) + } + + @Then("{actor} sees the proof is rejected") + fun bobSeesProofIsRejected(bob: Actor) { + wait( + { + proofEvent = ListenToEvents.`as`(bob).presentationEvents.lastOrNull { + it.data.thid == bob.recall("thid") + } + proofEvent != null && + proofEvent!!.data.status == PresentationStatus.Status.requestRejected + }, + "ERROR: Faber did not receive presentation from Bob!" + ) + } + + @Then("{actor} has the proof verified") + fun faberHasTheProofVerified(faber: Actor) { + wait( + { + proofEvent = ListenToEvents.`as`(faber).presentationEvents.lastOrNull { + it.data.thid == faber.recall("thid") + } + + proofEvent != null && + proofEvent!!.data.status == PresentationStatus.Status.presentationVerified + }, + "ERROR: presentation did not achieve PresentationVerified state!" + ) + } +} diff --git a/tests/integration-tests/src/test/kotlin/features/schemas/CredentialSchemasSteps.kt b/tests/integration-tests/src/test/kotlin/features/schemas/CredentialSchemasSteps.kt new file mode 100644 index 0000000000..c34af47855 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/schemas/CredentialSchemasSteps.kt @@ -0,0 +1,84 @@ +package features + +import common.TestConstants +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.prism.models.CredentialSchemaResponse +import models.Schema +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus.SC_CREATED +import org.apache.http.HttpStatus.SC_OK + +class CredentialSchemasSteps { + + @When("{actor} creates a new credential schema") + fun acmeCreatesANewCredentialSchema(actor: Actor) { + actor.attemptsTo( + Post.to("/schema-registry/schemas").with { + it.body( + TestConstants.STUDENT_SCHEMA.copy(author = actor.recall("shortFormDid")) + ) + } + ) + } + + @Then("{actor} sees new credential schema is available") + fun newCredentialSchemaIsAvailable(actor: Actor) { + val credentialSchema = SerenityRest.lastResponse().get() + val schema = SerenityRest.lastResponse().get("schema") + + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), + Ensure.that(credentialSchema.guid).isNotNull(), + Ensure.that(credentialSchema.id).isNotNull(), + Ensure.that(credentialSchema.longId!!).isNotNull(), + Ensure.that(credentialSchema.authored).isNotNull(), + Ensure.that(credentialSchema.kind).isEqualTo("CredentialSchema"), + Ensure.that(credentialSchema.name).contains(TestConstants.STUDENT_SCHEMA.name), + Ensure.that(credentialSchema.description).contains(TestConstants.STUDENT_SCHEMA.description!!), + Ensure.that(credentialSchema.version).contains(TestConstants.STUDENT_SCHEMA.version), + Ensure.that(credentialSchema.type).isEqualTo(TestConstants.CREDENTIAL_SCHEMA_TYPE), + Ensure.that(credentialSchema.tags!!).containsExactlyInAnyOrderElementsFrom(TestConstants.STUDENT_SCHEMA.tags!!), + Ensure.that(schema.toString()).isEqualTo(TestConstants.jsonSchema.toString()) + ) + } + + @When("{actor} creates {int} new schemas") + fun acmeCreatesMultipleSchemas(actor: Actor, numberOfSchemas: Int) { + val createdSchemas: MutableList = mutableListOf() + repeat(numberOfSchemas) { i: Int -> + actor.attemptsTo( + Post.to("/schema-registry/schemas").with { + it.body( + TestConstants.generate_with_name_suffix_and_author( + i.toString(), + actor.recall("shortFormDid") + ) + ) + } + ) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED) + ) + createdSchemas.add(SerenityRest.lastResponse().get()) + } + actor.remember("createdSchemas", createdSchemas) + } + + @Then("{actor} can access all of them one by one") + fun theyCanBeAccessedWithPagination(actor: Actor) { + actor.recall>("createdSchemas").forEach { schema -> + actor.attemptsTo( + Get.resource("/schema-registry/schemas/${schema.guid}") + ) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK) + ) + } + } +} diff --git a/tests/integration-tests/src/test/kotlin/features/system/SystemSteps.kt b/tests/integration-tests/src/test/kotlin/features/system/SystemSteps.kt new file mode 100644 index 0000000000..aaee61d9ec --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/system/SystemSteps.kt @@ -0,0 +1,31 @@ +package features.system + +import interactions.Get +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.prism.models.HealthInfo +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus + +class SystemSteps { + @When("{actor} makes a request to the health endpoint") + fun actorRequestsHealthEndpoint(actor: Actor) { + actor.attemptsTo( + Get.resource("/_system/health") + ) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK) + ) + } + + @Then("{actor} knows what version of the service is running") + fun actorUnderstandsVersion(actor: Actor) { + val healthResponse = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.that(healthResponse.version).isNotBlank() + ) + } +} diff --git a/tests/integration-tests/src/test/kotlin/features/verificationpolicies/VerificationPoliciesSteps.kt b/tests/integration-tests/src/test/kotlin/features/verificationpolicies/VerificationPoliciesSteps.kt new file mode 100644 index 0000000000..0b1ad616d9 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/features/verificationpolicies/VerificationPoliciesSteps.kt @@ -0,0 +1,100 @@ +package features.verificationpolicies + +import common.TestConstants +import interactions.Get +import interactions.Post +import interactions.Put +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.prism.models.VerificationPolicy +import io.iohk.atala.prism.models.VerificationPolicyInput +import net.serenitybdd.rest.SerenityRest +import net.serenitybdd.screenplay.Actor +import org.apache.http.HttpStatus +import java.util.* + +class VerificationPoliciesSteps { + + @When("{actor} creates a new verification policy") + fun acmeCreatesANewVerificationPolicy(actor: Actor) { + actor.attemptsTo( + Post.to("/verification/policies").with { + it.body( + TestConstants.TEST_VERIFICATION_POLICY + ) + } + ) + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_CREATED) + ) + } + + @Then("{actor} sees new verification policy is available") + fun newVerificationPolicyIsAvailable(actor: Actor) { + val policy = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.that(policy.id).isNotNull(), + Ensure.that(policy.nonce).isNotNull(), + Ensure.that(policy.kind).contains("VerificationPolicy"), + Ensure.that(policy.name).contains(TestConstants.TEST_VERIFICATION_POLICY.name), + Ensure.that(policy.description).contains(TestConstants.TEST_VERIFICATION_POLICY.description) + ) + + policy.constraints!!.forEach { + actor.attemptsTo( + Ensure.that(it.schemaId).isEqualTo(TestConstants.TEST_VERIFICATION_POLICY.constraints!!.first().schemaId), + Ensure.that(it.trustedIssuers!!) + .containsExactlyInAnyOrderElementsFrom( + TestConstants.TEST_VERIFICATION_POLICY.constraints!!.first().trustedIssuers!! + ) + ) + } + actor.remember("policy", policy) + } + + @When("{actor} updates a new verification policy") + fun acmeUpdatesAVerificationPolicy(actor: Actor) { + val policy = actor.recall("policy") + val updatePolicyInput = VerificationPolicyInput( + name = policy.name, + description = "updated description + ${UUID.randomUUID()}", + constraints = policy.constraints + ) + actor.attemptsTo( + Put.to("/verification/policies/${policy.id}?nonce=${policy.nonce}").with { + it.body(updatePolicyInput) + } + ) + actor.remember("updatedPolicyInput", updatePolicyInput) + } + + @Then("{actor} sees the updated verification policy is available") + fun updatedVerificationPolicyIsAvailable(actor: Actor) { + val updatePolicyInput = actor.forget("updatedPolicyInput") + + actor.attemptsTo( + Get.resource("/verification/policies/${actor.recall("policy").id}") + ) + val policy = SerenityRest.lastResponse().get() + + actor.attemptsTo( + Ensure.that(policy.id).isNotNull(), + Ensure.that(policy.nonce).isNotNull(), + Ensure.that(policy.kind).contains("VerificationPolicy"), + Ensure.that(policy.name).contains(updatePolicyInput.name), + Ensure.that(policy.description).contains(updatePolicyInput.description) + ) + + policy.constraints!!.forEach { + actor.attemptsTo( + Ensure.that(it.schemaId).isEqualTo(updatePolicyInput.constraints!!.first().schemaId), + Ensure.that(it.trustedIssuers!!) + .containsExactlyInAnyOrderElementsFrom( + updatePolicyInput.constraints!!.first().trustedIssuers!! + ) + ) + } + } +} diff --git a/tests/integration-tests/src/test/kotlin/interactions/AuthRestInteraction.kt b/tests/integration-tests/src/test/kotlin/interactions/AuthRestInteraction.kt new file mode 100644 index 0000000000..295fcae850 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/interactions/AuthRestInteraction.kt @@ -0,0 +1,25 @@ +package interactions + +import com.sksamuel.hoplite.ConfigLoader +import config.Config +import io.ktor.util.* +import io.restassured.specification.RequestSpecification +import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.rest.interactions.RestInteraction + +abstract class AuthRestInteraction : RestInteraction() { + + private val config = ConfigLoader().loadConfigOrThrow("/tests.conf") + + fun specWithAuthHeaders(actor: T): RequestSpecification { + val spec = rest() + if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { + spec.header(config.global.adminAuthHeader, config.admin.apikey) + } else { + if (config.global.authRequired) { + spec.header(config.global.authHeader, actor.recall("AUTH_KEY")) + } + } + return spec + } +} diff --git a/tests/e2e-tests/src/test/kotlin/interactions/Delete.kt b/tests/integration-tests/src/test/kotlin/interactions/Delete.kt similarity index 50% rename from tests/e2e-tests/src/test/kotlin/interactions/Delete.kt rename to tests/integration-tests/src/test/kotlin/interactions/Delete.kt index b70dd3da7b..4727abaad3 100644 --- a/tests/e2e-tests/src/test/kotlin/interactions/Delete.kt +++ b/tests/integration-tests/src/test/kotlin/interactions/Delete.kt @@ -1,30 +1,18 @@ package interactions -import common.Environments -import io.ktor.util.* import net.serenitybdd.annotations.Step import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.Tasks import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.interactions.RestInteraction - /** * This class is a copy of the class Delete from serenity rest interactions * to add a custom authentication header to the request on-the-fly. */ -open class Delete(private val resource: String) : RestInteraction() { +open class Delete(private val resource: String) : AuthRestInteraction() { @Step("{0} executes a DELETE on the resource #resource") override fun performAs(actor: T) { - val spec = rest() - if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { - spec.header(Environments.ADMIN_AUTH_HEADER, Environments.ADMIN_AUTH_TOKEN) - } else { - if (Environments.AGENT_AUTH_REQUIRED) { - spec.header(Environments.AGENT_AUTH_HEADER, actor.recall("AUTH_KEY")) - } - } - spec.delete(CallAnApi.`as`(actor).resolve(resource)) + specWithAuthHeaders(actor).delete(CallAnApi.`as`(actor).resolve(resource)) } companion object { diff --git a/tests/e2e-tests/src/test/kotlin/interactions/Get.kt b/tests/integration-tests/src/test/kotlin/interactions/Get.kt similarity index 50% rename from tests/e2e-tests/src/test/kotlin/interactions/Get.kt rename to tests/integration-tests/src/test/kotlin/interactions/Get.kt index f049f85d1f..c62b416cd8 100644 --- a/tests/e2e-tests/src/test/kotlin/interactions/Get.kt +++ b/tests/integration-tests/src/test/kotlin/interactions/Get.kt @@ -1,29 +1,18 @@ package interactions -import common.Environments -import io.ktor.util.* import net.serenitybdd.annotations.Step import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.Tasks import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.interactions.RestInteraction /** * This class is a copy of the class Get from serenity rest interactions * to add a custom authentication header to the request on-the-fly. */ -open class Get(private val resource: String) : RestInteraction() { +open class Get(private val resource: String) : AuthRestInteraction() { @Step("{0} executes a GET on the resource #resource") override fun performAs(actor: T) { - val spec = rest() - if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { - spec.header(Environments.ADMIN_AUTH_HEADER, Environments.ADMIN_AUTH_TOKEN) - } else { - if (Environments.AGENT_AUTH_REQUIRED) { - spec.header(Environments.AGENT_AUTH_HEADER, actor.recall("AUTH_KEY")) - } - } - spec.get(CallAnApi.`as`(actor).resolve(resource)) + specWithAuthHeaders(actor).get(CallAnApi.`as`(actor).resolve(resource)) } companion object { diff --git a/tests/e2e-tests/src/test/kotlin/interactions/Patch.kt b/tests/integration-tests/src/test/kotlin/interactions/Patch.kt similarity index 50% rename from tests/e2e-tests/src/test/kotlin/interactions/Patch.kt rename to tests/integration-tests/src/test/kotlin/interactions/Patch.kt index a48f463301..fbf874bbf5 100644 --- a/tests/e2e-tests/src/test/kotlin/interactions/Patch.kt +++ b/tests/integration-tests/src/test/kotlin/interactions/Patch.kt @@ -1,29 +1,18 @@ package interactions -import common.Environments -import io.ktor.util.* import net.serenitybdd.annotations.Step import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.Tasks import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.interactions.RestInteraction /** * This class is a copy of the class Patch from serenity rest interactions * to add a custom authentication header to the request on-the-fly. */ -open class Patch(private val resource: String) : RestInteraction() { +open class Patch(private val resource: String) : AuthRestInteraction() { @Step("{0} executes a PATCH on the resource #resource") override fun performAs(actor: T) { - val spec = rest() - if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { - spec.header(Environments.ADMIN_AUTH_HEADER, Environments.ADMIN_AUTH_TOKEN) - } else { - if (Environments.AGENT_AUTH_REQUIRED) { - spec.header(Environments.AGENT_AUTH_HEADER, actor.recall("AUTH_KEY")) - } - } - spec.patch(CallAnApi.`as`(actor).resolve(resource)) + specWithAuthHeaders(actor).patch(CallAnApi.`as`(actor).resolve(resource)) } companion object { diff --git a/tests/e2e-tests/src/test/kotlin/interactions/Post.kt b/tests/integration-tests/src/test/kotlin/interactions/Post.kt similarity index 50% rename from tests/e2e-tests/src/test/kotlin/interactions/Post.kt rename to tests/integration-tests/src/test/kotlin/interactions/Post.kt index 2104827f94..9b692867db 100644 --- a/tests/e2e-tests/src/test/kotlin/interactions/Post.kt +++ b/tests/integration-tests/src/test/kotlin/interactions/Post.kt @@ -1,29 +1,18 @@ package interactions -import common.Environments -import io.ktor.util.* import net.serenitybdd.annotations.Step import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.Tasks import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.interactions.RestInteraction /** * This class is a copy of the class Post from serenity rest interactions * to add a custom authentication header to the request on-the-fly. */ -open class Post(private val resource: String) : RestInteraction() { +open class Post(private val resource: String) : AuthRestInteraction() { @Step("{0} executes a POST on the resource #resource") override fun performAs(actor: T) { - val spec = rest() - if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { - spec.header(Environments.ADMIN_AUTH_HEADER, Environments.ADMIN_AUTH_TOKEN) - } else { - if (Environments.AGENT_AUTH_REQUIRED) { - spec.header(Environments.AGENT_AUTH_HEADER, actor.recall("AUTH_KEY")) - } - } - spec.post(CallAnApi.`as`(actor).resolve(resource)) + specWithAuthHeaders(actor).post(CallAnApi.`as`(actor).resolve(resource)) } companion object { diff --git a/tests/e2e-tests/src/test/kotlin/interactions/Put.kt b/tests/integration-tests/src/test/kotlin/interactions/Put.kt similarity index 50% rename from tests/e2e-tests/src/test/kotlin/interactions/Put.kt rename to tests/integration-tests/src/test/kotlin/interactions/Put.kt index 9326f9b0e5..4c2eeeeaa9 100644 --- a/tests/e2e-tests/src/test/kotlin/interactions/Put.kt +++ b/tests/integration-tests/src/test/kotlin/interactions/Put.kt @@ -1,30 +1,18 @@ package interactions -import common.Environments -import io.ktor.util.* import net.serenitybdd.annotations.Step import net.serenitybdd.screenplay.Actor import net.serenitybdd.screenplay.Tasks import net.serenitybdd.screenplay.rest.abilities.CallAnApi -import net.serenitybdd.screenplay.rest.interactions.RestInteraction - /** * This class is a copy of the class Put from serenity rest interactions * to add a custom authentication header to the request on-the-fly. */ -open class Put(private val resource: String) : RestInteraction() { +open class Put(private val resource: String) : AuthRestInteraction() { @Step("{0} executes a PUT on the resource #resource") override fun performAs(actor: T) { - val spec = rest() - if (actor!!.name.toLowerCasePreservingASCIIRules().contains("admin")) { - spec.header(Environments.ADMIN_AUTH_HEADER, Environments.ADMIN_AUTH_TOKEN) - } else { - if (Environments.AGENT_AUTH_REQUIRED) { - spec.header(Environments.AGENT_AUTH_HEADER, actor.recall("AUTH_KEY")) - } - } - spec.put(CallAnApi.`as`(actor).resolve(resource)) + specWithAuthHeaders(actor).put(CallAnApi.`as`(actor).resolve(resource)) } companion object { diff --git a/tests/e2e-tests/src/test/kotlin/runners/E2eTestsRunner.kt b/tests/integration-tests/src/test/kotlin/runners/E2eTestsRunner.kt similarity index 77% rename from tests/e2e-tests/src/test/kotlin/runners/E2eTestsRunner.kt rename to tests/integration-tests/src/test/kotlin/runners/E2eTestsRunner.kt index daab43ba4f..ee58f0f22f 100644 --- a/tests/e2e-tests/src/test/kotlin/runners/E2eTestsRunner.kt +++ b/tests/integration-tests/src/test/kotlin/runners/E2eTestsRunner.kt @@ -6,14 +6,14 @@ import org.junit.runner.RunWith @CucumberOptions( features = [ - "src/test/resources/features", + "src/test/resources/features" ], glue = ["features"], snippets = CucumberOptions.SnippetType.CAMELCASE, plugin = [ "pretty", - "json:target/serenity-reports/cucumber_report.json", - ], + "json:target/serenity-reports/cucumber_report.json" + ] ) @RunWith(CucumberWithSerenity::class) class E2eTestsRunner diff --git a/tests/integration-tests/src/test/resources/cucumber.properties b/tests/integration-tests/src/test/resources/cucumber.properties new file mode 100644 index 0000000000..170a3740bb --- /dev/null +++ b/tests/integration-tests/src/test/resources/cucumber.properties @@ -0,0 +1,2 @@ +cucumber.publish.quiet=true +cucumber.object-factory=io.iohk.atala.automation.serenity.objectfactory.AtalaObjectFactory \ No newline at end of file diff --git a/tests/e2e-tests/src/test/resources/features/connection/connection.feature b/tests/integration-tests/src/test/resources/features/connection/connection.feature similarity index 86% rename from tests/e2e-tests/src/test/resources/features/connection/connection.feature rename to tests/integration-tests/src/test/resources/features/connection/connection.feature index 6254ba419f..02d1150932 100644 --- a/tests/e2e-tests/src/test/resources/features/connection/connection.feature +++ b/tests/integration-tests/src/test/resources/features/connection/connection.feature @@ -3,7 +3,6 @@ Feature: Agents connection @TEST_ATL-3834 Scenario: Establish a connection between two agents When Acme generates a connection invitation to Bob - And Bob receives the connection invitation from Acme And Bob sends a connection request to Acme And Acme receives the connection request and sends back the response And Bob receives the connection response diff --git a/tests/e2e-tests/src/test/resources/features/issue_credentials/issue_credentials.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/issue_credentials/issue_credentials.feature rename to tests/integration-tests/src/test/resources/features/credentials/issue_credentials.feature diff --git a/tests/e2e-tests/src/test/resources/features/did_registrar/create_did.feature b/tests/integration-tests/src/test/resources/features/did/create_did.feature similarity index 75% rename from tests/e2e-tests/src/test/resources/features/did_registrar/create_did.feature rename to tests/integration-tests/src/test/resources/features/did/create_did.feature index 90d8b3b23a..828ea34d47 100644 --- a/tests/e2e-tests/src/test/resources/features/did_registrar/create_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/create_did.feature @@ -25,12 +25,11 @@ Scenario Outline: PRISM DID creation fails with wrong formatted fields Given Acme tries to create a managed DID with value in Then He sees the request has failed with error status Examples: - | field | value | error | - | documentTemplate.publicKeys[0].id | # | 422 | - | documentTemplate.publicKeys[0].purpose | potato | 400 | - | documentTemplate.services[0].id | # | 422 | - | documentTemplate.services[0].type | pot@to | 422 | - | documentTemplate.services[0].serviceEndpoint[0] | potato | 422 | + | field | value | error | + | documentTemplate.publicKeys[0].id | # | 422 | + | documentTemplate.publicKeys[0].purpose | potato | 400 | + | documentTemplate.services[0].id | # | 422 | + | documentTemplate.services[0].type | pot@to | 422 | @TEST_ATL-3842 Scenario: Successfully publish DID to ledger diff --git a/tests/e2e-tests/src/test/resources/features/did_registrar/deactivate_did.feature b/tests/integration-tests/src/test/resources/features/did/deactivate_did.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/did_registrar/deactivate_did.feature rename to tests/integration-tests/src/test/resources/features/did/deactivate_did.feature diff --git a/tests/e2e-tests/src/test/resources/features/did_registrar/listing_did.feature b/tests/integration-tests/src/test/resources/features/did/listing_did.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/did_registrar/listing_did.feature rename to tests/integration-tests/src/test/resources/features/did/listing_did.feature diff --git a/tests/e2e-tests/src/test/resources/features/did_registrar/update_did.feature b/tests/integration-tests/src/test/resources/features/did/update_did.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/did_registrar/update_did.feature rename to tests/integration-tests/src/test/resources/features/did/update_did.feature diff --git a/tests/e2e-tests/src/test/resources/features/multitenancy/wallets.feature b/tests/integration-tests/src/test/resources/features/multitenancy/wallets.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/multitenancy/wallets.feature rename to tests/integration-tests/src/test/resources/features/multitenancy/wallets.feature diff --git a/tests/e2e-tests/src/test/resources/features/present_proof/present_proof.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/present_proof/present_proof.feature rename to tests/integration-tests/src/test/resources/features/proofs/present_proof.feature diff --git a/tests/e2e-tests/src/test/resources/features/credential_schemas/credential_schemas.feature b/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/credential_schemas/credential_schemas.feature rename to tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature diff --git a/tests/e2e-tests/src/test/resources/features/system/health_endpoint.feature b/tests/integration-tests/src/test/resources/features/system/health_endpoint.feature similarity index 100% rename from tests/e2e-tests/src/test/resources/features/system/health_endpoint.feature rename to tests/integration-tests/src/test/resources/features/system/health_endpoint.feature diff --git a/tests/e2e-tests/src/test/resources/features/verification_policies/verification_policies.feature b/tests/integration-tests/src/test/resources/features/verificationpolicies/verification_policies.feature similarity index 74% rename from tests/e2e-tests/src/test/resources/features/verification_policies/verification_policies.feature rename to tests/integration-tests/src/test/resources/features/verificationpolicies/verification_policies.feature index 0b14be8b8a..766319b2f9 100644 --- a/tests/e2e-tests/src/test/resources/features/verification_policies/verification_policies.feature +++ b/tests/integration-tests/src/test/resources/features/verificationpolicies/verification_policies.feature @@ -6,5 +6,3 @@ Scenario: Successful verification policy creation Then He sees new verification policy is available When He updates a new verification policy Then He sees the updated verification policy is available - When He updates a new verification policy - Then He sees the updated verification policy is available diff --git a/tests/e2e-tests/src/test/resources/log4j.properties b/tests/integration-tests/src/test/resources/log4j.properties similarity index 100% rename from tests/e2e-tests/src/test/resources/log4j.properties rename to tests/integration-tests/src/test/resources/log4j.properties diff --git a/tests/e2e-tests/src/test/resources/scripts/add_test_execution.py b/tests/integration-tests/src/test/resources/scripts/add_test_execution.py similarity index 100% rename from tests/e2e-tests/src/test/resources/scripts/add_test_execution.py rename to tests/integration-tests/src/test/resources/scripts/add_test_execution.py diff --git a/tests/e2e-tests/src/test/resources/scripts/requirements.txt b/tests/integration-tests/src/test/resources/scripts/requirements.txt similarity index 100% rename from tests/e2e-tests/src/test/resources/scripts/requirements.txt rename to tests/integration-tests/src/test/resources/scripts/requirements.txt diff --git a/tests/integration-tests/src/test/resources/tests.conf b/tests/integration-tests/src/test/resources/tests.conf new file mode 100644 index 0000000000..5b617bbe89 --- /dev/null +++ b/tests/integration-tests/src/test/resources/tests.conf @@ -0,0 +1,31 @@ +global { + auth_required = true + auth_header = "apikey" + admin_auth_header = "x-admin-api-key" +} + +admin { + url = "${ADMIN_AGENT_URL:-http://localhost:8080/prism-agent}" + apikey = "${ADMIN_API_KEY:-admin}" +} + +issuer { + url = "${ISSUER_AGENT_URL:-http://localhost:8080/prism-agent}" + webhook_url = "${ISSUER_WEBHOOK_URL:-http://host.docker.internal:9955}" + apikey = "${ISSUER_API_KEY:-${random.string(16)}}" +} + +holder { + url = "http://localhost:8090/prism-agent" + url = ${?HOLDER_AGENT_URL} + webhook_url = "http://host.docker.internal:9956" + webhook_url = ${?HOLDER_WEBHOOK_URL} + apikey = "default" + apikey = ${?HOLDER_API_KEY} +} + +verifier { + url = "${VERIFIER_AGENT_URL:-http://localhost:8080/prism-agent}" + webhook_url = "${VERIFIER_WEBHOOK_URL:-http://host.docker.internal:9957}" + apikey = "${VERIFIER_API_KEY:-${random.string(16)}}" +}