Skip to content

Commit

Permalink
test(connect): add unit tests on connect and issue
Browse files Browse the repository at this point in the history
* test(connect): add basic unit tests

* test(connect): add more unit tests

* test(connect): add more unit tests

* test(connect): add tests for repo component

* test(connect): use test-containers and add more tests

* test(connect): add sbt-scoverage plugin

* chore(connect): run scalafmt

* test(connect): cover hikari transactor code

* feat(connect): add ConnectionRepositoryError class

* feat(connect): check 'thid' unicity in in-memory repo implemention when creating record

* test(connect): add unit test for in-memory repo impl

* feat(connect): map 'PSQLException' to 'UniqueConstraintViolation' repo error in JDBC implementation

* test(connect): reuse the repository interface test suite from 'core' for JDBC implementation

* doc(connect): add state diagram for connect flow

* doc(pollux): add state diagram for issue flow

* chore(pollux): decouple credential service trait from implementation

* feat(pollux): add CredentialRepositoryError sealed trait

* feat(pollux): add CredentialRepositoryInMemory implementation

* test(pollux): add basic unit test

* chore(pollux): unignore 'projet' folder which is declared in top-level .gitignore

* chore(pollux): add scoverage plugin

* test(connect): fix unit tests

* feat(pollux): add delete method to credential repository

* feat(pollux): add CredentialRepositoryInMemory implementation

* test(pollux): add in-memory credential repository spec

* feat(pollux): implement delete method in Jdbc repository

* chore(pollux): add unique constraint on 'issue_credential_records.thid'

* chore(pollux): fix JdbcCredentialRepository queries

* chore(pollux): add integration tests for JdbcCredentialRepository

* Update connect/lib/core/src/main/scala/io/iohk/atala/connect/core/repository/ConnectionRepositoryInMemory.scala

Co-authored-by: Yurii Shynbuiev - IOHK <[email protected]>

* test(pollux): fix Option assertions in unit tests

* test(pollux): fix Option assertions in unit tests

Co-authored-by: Yurii Shynbuiev - IOHK <[email protected]>
  • Loading branch information
bvoiturier and yshyn-iohk authored Jan 25, 2023
1 parent da288bf commit 1bbb02f
Show file tree
Hide file tree
Showing 31 changed files with 2,146 additions and 561 deletions.
10 changes: 6 additions & 4 deletions connect/lib/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import sbtrelease.ReleasePlugin.autoImport.ReleaseTransformations._
inThisBuild(
Seq(
organization := "io.iohk.atala",
scalaVersion := "3.2.1",
scalaVersion := "3.2.2",
fork := true,
run / connectInput := true,
versionScheme := Some("semver-spec"),
Expand All @@ -18,7 +18,8 @@ val commonSettings = Seq(
githubTokenSource := TokenSource.Environment("ATALA_GITHUB_TOKEN"),
resolvers += Resolver.githubPackages("input-output-hk"),
// Needed for Kotlin coroutines that support new memory management mode
resolvers += "JetBrains Space Maven Repository" at "https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven"
resolvers += "JetBrains Space Maven Repository" at "https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven",
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

// Project definitions
Expand All @@ -34,7 +35,8 @@ lazy val core = project
.settings(commonSettings)
.settings(
name := "connect-core",
libraryDependencies ++= coreDependencies
libraryDependencies ++= coreDependencies,
Test / publishArtifact := true
)

lazy val `sql-doobie` = project
Expand All @@ -44,7 +46,7 @@ lazy val `sql-doobie` = project
name := "connect-sql-doobie",
libraryDependencies ++= sqlDoobieDependencies
)
.dependsOn(core)
.dependsOn(core % "compile->compile;test->test")

// ### ReleaseStep ###
releaseProcess := Seq[ReleaseStep](
Expand Down
23 changes: 23 additions & 0 deletions connect/lib/connect-protocol-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
```mermaid
---
title: Inviter Connect State
---
stateDiagram-v2
[*] --> InvitationGenerated: generate and share new OOB invitation
InvitationGenerated --> ConnectionRequestReceived: receive connection request
ConnectionRequestReceived --> ConnectionResponsePending: accept connection request
ConnectionResponsePending --> ConnectionResponseSent: send connection response (via DIDComm Agent)
ConnectionResponseSent --> [*]
```
---
```mermaid
---
title: Invitee Connect State
---
stateDiagram-v2
[*] --> InvitationReceived: receive OOB invitation
InvitationReceived --> ConnectionRequestPending: accept invitation
ConnectionRequestPending --> ConnectionRequestSent: send connection request (via DIDComm Agent)
ConnectionRequestSent --> ConnectionResponseReceived: receive connection response
ConnectionResponseReceived --> [*]
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.iohk.atala.connect.core.model.error

sealed trait ConnectionRepositoryError extends Throwable

object ConnectionRepositoryError {
final case class UniqueConstraintViolation(message: String) extends ConnectionRepositoryError
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ trait ConnectionRepository[F[_]] {

def updateWithConnectionRequest(recordId: UUID, request: ConnectionRequest, state: ProtocolState): F[Int]

def updateWithConnectionResponse(recordId: UUID, request: ConnectionResponse, state: ProtocolState): F[Int]
def updateWithConnectionResponse(recordId: UUID, response: ConnectionResponse, state: ProtocolState): F[Int]

def updateConnectionProtocolState(recordId: UUID, from: ProtocolState, to: ProtocolState): F[Int]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package io.iohk.atala.connect.core.repository

import io.iohk.atala.connect.core.model.ConnectionRecord
import io.iohk.atala.connect.core.model.error.ConnectionRepositoryError._
import io.iohk.atala.connect.core.model.ConnectionRecord.ProtocolState
import io.iohk.atala.mercury.protocol.connection.ConnectionRequest
import io.iohk.atala.mercury.protocol.connection.ConnectionResponse
import zio._

import java.time.Instant
import java.util.UUID

class ConnectionRepositoryInMemory(storeRef: Ref[Map[UUID, ConnectionRecord]]) extends ConnectionRepository[Task] {

override def updateWithConnectionResponse(
recordId: UUID,
response: ConnectionResponse,
state: ProtocolState
): Task[Int] = {
for {
maybeRecord <- getConnectionRecord(recordId)
count <- maybeRecord
.map(record =>
for {
_ <- storeRef.update(r =>
r.updated(
recordId,
record.copy(
updatedAt = Some(Instant.now),
connectionResponse = Some(response),
protocolState = state
)
)
)
} yield 1
)
.getOrElse(ZIO.succeed(1))
} yield count
}

override def updateConnectionProtocolState(recordId: UUID, from: ProtocolState, to: ProtocolState): Task[Int] = {
for {
store <- storeRef.get
maybeRecord = store
.find((uuid, record) => uuid == recordId && record.protocolState == from)
.map(_._2)
count <- maybeRecord
.map(record =>
for {
_ <- storeRef.update(r => r.updated(recordId, record.copy(protocolState = to)))
} yield 1
)
.getOrElse(ZIO.succeed(0))
} yield count
}

override def deleteConnectionRecord(recordId: UUID): Task[Int] = {
for {
maybeRecord <- getConnectionRecord(recordId)
count <- maybeRecord
.map(record =>
for {
_ <- storeRef.update(r => r.removed(recordId))
} yield 1
)
.getOrElse(ZIO.succeed(0))
} yield count
}

override def updateWithConnectionRequest(
recordId: UUID,
request: ConnectionRequest,
state: ProtocolState
): Task[Int] = {
for {
maybeRecord <- getConnectionRecord(recordId)
count <- maybeRecord
.map(record =>
for {
_ <- storeRef.update(r =>
r.updated(
recordId,
record.copy(
updatedAt = Some(Instant.now),
connectionRequest = Some(request),
protocolState = state
)
)
)
} yield 1
)
.getOrElse(ZIO.succeed(1))
} yield count
}

override def getConnectionRecordByThreadId(thid: UUID): Task[Option[ConnectionRecord]] = {
for {
store <- storeRef.get
} yield store.values.find(_.thid.contains(thid))
}

override def getConnectionRecords(): Task[Seq[ConnectionRecord]] = {
for {
store <- storeRef.get
} yield store.values.toSeq
}

override def createConnectionRecord(record: ConnectionRecord): Task[Int] = {
for {
_ <- record.thid match
case None => ZIO.unit
case Some(value) =>
for {
store <- storeRef.get
maybeRecord <- ZIO.succeed(store.values.find(_.thid == record.thid))
_ <- maybeRecord match
case None => ZIO.unit
case Some(value) => ZIO.fail(UniqueConstraintViolation("Unique Constraint Violation on 'thid'"))
} yield ()
_ <- storeRef.update(r => r + (record.id -> record))
} yield 1
}

override def getConnectionRecord(recordId: UUID): Task[Option[ConnectionRecord]] = {
for {
store <- storeRef.get
record = store.get(recordId)
} yield record
}

}

object ConnectionRepositoryInMemory {
val layer: ULayer[ConnectionRepository[Task]] = ZLayer.fromZIO(
Ref
.make(Map.empty[UUID, ConnectionRecord])
.map(ConnectionRepositoryInMemory(_))
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ import io.iohk.atala.mercury.protocol.connection.ConnectionResponse

trait ConnectionService {

def createConnectionInvitation(label: Option[String], pairwiseDID: DidId): IO[ConnectionServiceError, ConnectionRecord]
def createConnectionInvitation(
label: Option[String],
pairwiseDID: DidId
): IO[ConnectionServiceError, ConnectionRecord]

def receiveConnectionInvitation(invitation: String): IO[ConnectionServiceError, ConnectionRecord]

def acceptConnectionInvitation(recordId: UUID, pairwiseDid: DidId): IO[ConnectionServiceError, Option[ConnectionRecord]]
def acceptConnectionInvitation(
recordId: UUID,
pairwiseDid: DidId
): IO[ConnectionServiceError, Option[ConnectionRecord]]

def markConnectionRequestSent(recordId: UUID): IO[ConnectionServiceError, Option[ConnectionRecord]]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.iohk.atala.connect.core.repository

import io.iohk.atala.connect.core.model.ConnectionRecord
import io.iohk.atala.connect.core.model.ConnectionRecord._
import io.iohk.atala.connect.core.repository.ConnectionRepository
import io.iohk.atala.connect.core.repository.ConnectionRepositoryInMemory
import io.iohk.atala.mercury.model.DidId
import io.iohk.atala.mercury.protocol.connection.ConnectionRequest
import io.iohk.atala.mercury.protocol.connection.ConnectionResponse
import io.iohk.atala.mercury.protocol.invitation.v2.Invitation
import zio._
import zio.test.Assertion._
import zio.test._

import java.sql.SQLException
import java.time.Instant
import java.util.UUID

object ConnectionRepositoryInMemorySpec extends ZIOSpecDefault {

override def spec: Spec[TestEnvironment with Scope, Any] =
suite("In Memory Connection Repository test suite")(ConnectionRepositorySpecSuite.testSuite).provide(
ConnectionRepositoryInMemory.layer
)

}
Loading

0 comments on commit 1bbb02f

Please sign in to comment.