Skip to content

Commit

Permalink
test: add verification scenarios
Browse files Browse the repository at this point in the history
Signed-off-by: Allain Magyar <allain.magyar@iohk.io>
  • Loading branch information
amagyar-iohk committed Jul 17, 2024
1 parent 985ac26 commit 7bf9f42
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 44 deletions.
6 changes: 2 additions & 4 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
@goncalo-frade-iohk @yshyn-iohk @elribonazo @hamada147 @cristianIOHK
@elribonazo @cristianIOHK

# Test related:
/sampleapp/ @amagyar-iohk @todorkoleviohk @hamada147 @cristianIOHK
/tests/ @amagyar-iohk @todorkoleviohk @hamada147 @cristianIOHK
/tests/ @amagyar-iohk

# Docs:
*.md @petevielhaber

Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,9 @@ class ConnectionManagerImpl(
}
}
}

// Fallback mechanism if no WebSocket service endpoint is available
if (serviceEndpoint == null) {
while (true) {
while (fetchingMessagesJob!!.isActive) {
// Continuously await and process new messages
awaitMessages().collect { array ->
processMessages(array)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.junit.runner.RunWith
@RunWith(CucumberWithSerenity::class)
@CucumberOptions(
features = ["src/test/resources/features"],
plugin = ["pretty"]
plugin = ["pretty"],
tags = "not @disabled"
)
class TestSuite
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import io.iohk.atala.automation.utils.Logger
import io.restassured.RestAssured
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.serenitybdd.screenplay.Ability
import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.HasTeardown
import net.serenitybdd.screenplay.Question
import net.serenitybdd.screenplay.SilentInteraction
import org.hyperledger.identus.walletsdk.apollo.ApolloImpl
Expand All @@ -24,7 +26,11 @@ import org.hyperledger.identus.walletsdk.edgeagent.EdgeAgent
import org.hyperledger.identus.walletsdk.edgeagent.helpers.AgentOptions
import org.hyperledger.identus.walletsdk.edgeagent.helpers.Experiments
import org.hyperledger.identus.walletsdk.edgeagent.mediation.BasicMediatorHandler
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType.DidcommIssueCredential
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType.DidcommOfferCredential
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType.DidcommPresentation
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType.DidcommRequestPresentation
import org.hyperledger.identus.walletsdk.edgeagent.protocols.ProtocolType.PrismRevocation
import org.hyperledger.identus.walletsdk.mercury.MercuryImpl
import org.hyperledger.identus.walletsdk.mercury.resolvers.DIDCommWrapper
import org.hyperledger.identus.walletsdk.pluto.PlutoImpl
Expand All @@ -34,7 +40,7 @@ import java.util.Base64
import java.util.Collections


class UseWalletSdk : Ability {
class UseWalletSdk : Ability, HasTeardown {
companion object {
private fun `as`(actor: Actor): UseWalletSdk {
if (actor.abilityTo(UseWalletSdk::class.java) != null) {
Expand Down Expand Up @@ -70,36 +76,29 @@ class UseWalletSdk : Ability {
}
}

fun execute(callback: suspend (sdk: SdkContext) -> Unit): SilentInteraction {
return object : SilentInteraction() {
override fun <T : Actor> performAs(actor: T) {
val asActor = `as`(actor)
runBlocking {
callback(asActor.context)
}
}
fun presentationStackSize(): Question<Int> {
return Question.about("presentation messages stack").answeredBy {
`as`(it).context.presentationStack.size
}
}

fun stop(): SilentInteraction {
fun execute(callback: suspend (sdk: SdkContext) -> Unit): SilentInteraction {
return object : SilentInteraction() {
override fun <T : Actor> performAs(actor: T) {
val walletSdk = `as`(actor)
val asActor = `as`(actor)
runBlocking {
walletSdk.context.sdk.stopFetchingMessages()
walletSdk.context.sdk.stop()
walletSdk.isInitialized = false
callback(asActor.context)
}
}

}
}
}

private val logger = Logger.get<EdgeAgentWorkflow>()
lateinit var context: SdkContext
private lateinit var context: SdkContext
private val receivedMessages = mutableListOf<String>()
private var isInitialized = false
private lateinit var fetchJob: Job

fun initialize() {
createSdk()
Expand Down Expand Up @@ -168,18 +167,19 @@ class UseWalletSdk : Ability {
}

private fun listenToMessages() {
CoroutineScope(Dispatchers.Default).launch {
fetchJob = CoroutineScope(Dispatchers.Default).launch {
context.sdk.handleReceivedMessagesEvents().collect { messageList: List<Message> ->
messageList.forEach { message ->
if (receivedMessages.contains(message.id)) {
return@forEach
}
receivedMessages.add(message.id)
when (message.piuri) {
ProtocolType.DidcommOfferCredential.value -> context.credentialOfferStack.add(message)
ProtocolType.DidcommIssueCredential.value -> context.issuedCredentialStack.add(message)
ProtocolType.DidcommRequestPresentation.value -> context.proofRequestStack.add(message)
ProtocolType.PrismRevocation.value -> context.revocationNotificationStack.add(message)
DidcommOfferCredential.value -> context.credentialOfferStack.add(message)
DidcommIssueCredential.value -> context.issuedCredentialStack.add(message)
DidcommRequestPresentation.value -> context.proofRequestStack.add(message)
PrismRevocation.value -> context.revocationNotificationStack.add(message)
DidcommPresentation.value -> context.presentationStack.add(message)
else -> logger.debug("other message: ${message.piuri}")
}
}
Expand All @@ -195,14 +195,21 @@ class UseWalletSdk : Ability {
val json = JsonPath.parse(decodedData)
return json.read("from")
}

override fun tearDown() {
context.sdk.stopFetchingMessages()
context.sdk.stop()
fetchJob.cancel()
}
}

data class SdkContext(
val sdk: EdgeAgent,
val credentialOfferStack: MutableList<Message> = Collections.synchronizedList(mutableListOf()),
val proofRequestStack: MutableList<Message> = Collections.synchronizedList(mutableListOf()),
val issuedCredentialStack: MutableList<Message> = Collections.synchronizedList(mutableListOf()),
val revocationNotificationStack: MutableList<Message> = Collections.synchronizedList(mutableListOf())
val revocationNotificationStack: MutableList<Message> = Collections.synchronizedList(mutableListOf()),
val presentationStack: MutableList<Message> = Collections.synchronizedList(mutableListOf())
)

class ActorCannotUseWalletSdk(actor: Actor) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class HooksSetup {
UseWalletSdk()
)

cast.actorNamed("Verifier Edge Agent",
CallAnApi.at(Environment.mediatorOobUrl),
UseWalletSdk()
)

cast.actorNamed("Cloud Agent",
CallAnApi.at(Environment.agentUrl),
UseWalletSdk()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.hyperledger.identus.walletsdk.steps

import io.cucumber.java.After
import io.cucumber.java.en.Given
import io.cucumber.java.en.Then
import io.cucumber.java.en.When
import kotlinx.coroutines.flow.first
import net.serenitybdd.screenplay.Actor
import net.serenitybdd.screenplay.actors.OnStage
import org.hyperledger.identus.walletsdk.abilities.UseWalletSdk
import org.hyperledger.identus.walletsdk.domain.models.CredentialType
import org.hyperledger.identus.walletsdk.domain.models.DID
import org.hyperledger.identus.walletsdk.domain.models.InputFieldFilter
import org.hyperledger.identus.walletsdk.domain.models.PresentationClaims
import org.hyperledger.identus.walletsdk.workflow.CloudAgentWorkflow
import org.hyperledger.identus.walletsdk.workflow.EdgeAgentWorkflow
import javax.inject.Inject
Expand Down Expand Up @@ -123,6 +126,38 @@ class EdgeAgentSteps {
edgeAgentWorkflow.presentProof(edgeAgent)
}

@When("{actor} request {actor} to verify the JWT credential")
fun `Verifier requests Holder to verify the JWT Credential`(verifierEdgeAgent: Actor, holderEdgeAgent: Actor) {
edgeAgentWorkflow.createPeerDids(holderEdgeAgent, 1)
val did = holderEdgeAgent.recall<DID>("did")
val claims = PresentationClaims(
claims = mapOf(
"automation-required" to InputFieldFilter(type = "string", pattern = "required value")
)
)
edgeAgentWorkflow.initiatePresentationRequest(CredentialType.JWT, verifierEdgeAgent, did, claims)
}

@When("{actor} request {actor} to verify the anonymous credential")
fun `Verifier requests Holder to verify the anoncred credential`(verifierEdgeAgent: Actor, holderEdgeAgent: Actor) {
edgeAgentWorkflow.createPeerDids(holderEdgeAgent, 1)
val did = holderEdgeAgent.recall<DID>("did")
// FIXME: change to anoncred attributes request
val claims = PresentationClaims(
claims = mapOf(
"name" to InputFieldFilter(type = "string", pattern = "automation")
)
)
// FIXME: change to CredentialType.AnonCred
edgeAgentWorkflow.initiatePresentationRequest(CredentialType.JWT, verifierEdgeAgent, did, claims)
}

@When("{actor} sends the verification proof")
fun `Edge Agent sends the verification proof`(edgeAgent: Actor) {
edgeAgentWorkflow.waitForProofRequest(edgeAgent)
edgeAgentWorkflow.presentProof(edgeAgent)
}

@Then("{actor} should receive the credential")
fun `Edge Agent should receive the credential`(edgeAgent: Actor) {
edgeAgentWorkflow.waitForCredentialOffer(edgeAgent, 1)
Expand All @@ -148,6 +183,15 @@ class EdgeAgentSteps {
//edgeAgentWorkflow.creden
}

@Given("{actor} has 0 issued credentials")
fun `Edge agent test`(actor: Actor) {
actor.attemptsTo(
UseWalletSdk.execute {
assert(it.sdk.getAllCredentials().first().isEmpty())
}
)
}

@Then("{actor} waits to receive the revocation notifications from {actor}")
fun `Edge Agent waits to receive the revocation notifications from Cloud Agent`(
edgeAgent: Actor,
Expand Down Expand Up @@ -191,10 +235,15 @@ class EdgeAgentSteps {
edgeAgent.wrapUp()
}

@After
fun stopAgent() {
OnStage.theActor("Edge Agent").attemptsTo(
UseWalletSdk.stop()
)
@Then("{actor} should see the verification proof is verified")
fun `Verifier Edge Agent should see the verification proof is verified`(verifierEdgeAgent: Actor) {
edgeAgentWorkflow.waitForPresentationMessage(verifierEdgeAgent)
edgeAgentWorkflow.verifyPresentation(verifierEdgeAgent)
}

@Then("{actor} should see the verification proof was not verified due revocation")
fun `Verifier Edge Agent should see the verification proof was not verified`(verifierEdgeAgent: Actor) {
edgeAgentWorkflow.waitForPresentationMessage(verifierEdgeAgent)
edgeAgentWorkflow.verifyPresentation(verifierEdgeAgent, expected = false, shouldBeRevoked = true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class CloudAgentWorkflow {
fun offerJwtCredential(cloudAgent: Actor) {
val connectionId = cloudAgent.recall<String>("connectionId")
val credential = CreateIssueCredentialRecordRequest(
claims = mapOf(Pair("automation-required", UUID.randomUUID())),
claims = mapOf(Pair("automation-required", "required value")),
issuingDID = Environment.publishedDid,
connectionId = UUID.fromString(connectionId),
schemaId = "${Environment.agentUrl}/schema-registry/schemas/${Environment.jwtSchemaGuid}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import io.iohk.atala.automation.utils.Logger
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
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.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.fail
Expand All @@ -17,12 +15,19 @@ import org.hyperledger.identus.walletsdk.abilities.UseWalletSdk
import org.hyperledger.identus.walletsdk.apollo.ApolloImpl
import org.hyperledger.identus.walletsdk.configuration.Environment
import org.hyperledger.identus.walletsdk.domain.models.CastorError
import org.hyperledger.identus.walletsdk.domain.models.CredentialType
import org.hyperledger.identus.walletsdk.domain.models.DID
import org.hyperledger.identus.walletsdk.domain.models.PolluxError
import org.hyperledger.identus.walletsdk.domain.models.PresentationClaims
import org.hyperledger.identus.walletsdk.domain.models.Seed
import org.hyperledger.identus.walletsdk.edgeagent.protocols.issueCredential.IssueCredential
import org.hyperledger.identus.walletsdk.edgeagent.protocols.issueCredential.OfferCredential
import org.hyperledger.identus.walletsdk.edgeagent.protocols.outOfBand.OutOfBandInvitation
import org.hyperledger.identus.walletsdk.edgeagent.protocols.proofOfPresentation.RequestPresentation
import org.hyperledger.identus.walletsdk.pluto.PlutoBackupTask
import java.util.UUID
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes

class EdgeAgentWorkflow {
private val logger = Logger.get<EdgeAgentWorkflow>()
Expand Down Expand Up @@ -61,7 +66,6 @@ class EdgeAgentWorkflow {
UseWalletSdk.proofOfRequestStackSize(),
equalTo(1)
)

)
}

Expand Down Expand Up @@ -129,7 +133,7 @@ class EdgeAgentWorkflow {

fun waitForCredentialRevocationMessage(edgeAgent: Actor, numberOfRevocation: Int) {
edgeAgent.attemptsTo(
PollingWait.until(
PollingWait.with(2.minutes, 500.milliseconds).until(
UseWalletSdk.revocationStackSize(),
equalTo(numberOfRevocation)
)
Expand Down Expand Up @@ -169,7 +173,7 @@ class EdgeAgentWorkflow {
val walletSdk = UseWalletSdk()
walletSdk.recoverWallet(seed, backup)
runBlocking {
walletSdk.context.sdk.stop()
walletSdk.tearDown()
}
}

Expand All @@ -191,7 +195,8 @@ class EdgeAgentWorkflow {
edgeAgent.attemptsTo(
UseWalletSdk.execute { sdkContext ->
repeat(numberOfDids) {
sdkContext.sdk.createNewPeerDID(updateMediator = false)
val did = sdkContext.sdk.createNewPeerDID(updateMediator = true)
edgeAgent.remember("did", did)
}
}
)
Expand Down Expand Up @@ -243,4 +248,37 @@ class EdgeAgentWorkflow {
}
)
}

fun initiatePresentationRequest(type: CredentialType, edgeAgent: Actor, did: DID, claims: PresentationClaims) {
edgeAgent.attemptsTo(
UseWalletSdk.execute {
it.sdk.initiatePresentationRequest(type, did, claims, "", UUID.randomUUID().toString())
}
)
}

fun waitForPresentationMessage(edgeAgent: Actor, numberOfMessages: Int = 1) {
edgeAgent.attemptsTo(
PollingWait.until(
UseWalletSdk.presentationStackSize(),
equalTo(numberOfMessages)
)
)
}

fun verifyPresentation(edgeAgent: Actor, expected: Boolean = true, shouldBeRevoked: Boolean = false) {
edgeAgent.attemptsTo(
UseWalletSdk.execute {
val message = it.presentationStack.removeFirst()
try {
val isVerified = it.sdk.handlePresentation(message)
assertThat(isVerified).isEqualTo(expected)
} catch (e: PolluxError.VerificationUnsuccessful) {
assertThat(expected).isFalse()
assertThat(shouldBeRevoked).isTrue()
assertThat(e.message).contains("Provided credential is revoked")
}
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Feature: Backup
The Edge Agent should be able to create and restore a backup

@test
Scenario: Create and restore a backup
Given Edge Agent has created a backup
Then a new SDK can be restored from Edge Agent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@anoncreds @verification
Feature: Verify Anoncreds presentation
The Edge Agent should be able to receive a verifiable credential from Cloud Agent and then send a presentation to another edge agent who will verify it

@disabled
Scenario: SDKs Anoncreds Verification
Given Cloud Agent is connected to Edge Agent
And Edge Agent has '1' anonymous credentials issued by Cloud Agent
When Verifier Edge Agent request Edge Agent to verify the anonymous credential
When Edge Agent sends the verification proof
Then Verifier Edge Agent should see the verification proof is verified
Loading

0 comments on commit 7bf9f42

Please sign in to comment.