Skip to content

Commit

Permalink
wip: add tests
Browse files Browse the repository at this point in the history
Signed-off-by: Pat Losoponkul <pat.losoponkul@iohk.io>
  • Loading branch information
patlo-iog committed May 9, 2024
1 parent 26cf243 commit 3596a50
Show file tree
Hide file tree
Showing 4 changed files with 319 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.hyperledger.identus.pollux.core.model.CredentialFormat

import java.net.URI
import java.time.Instant
import java.time.temporal.ChronoUnit

final case class CredentialConfiguration(
configurationId: String,
Expand All @@ -12,4 +13,8 @@ final case class CredentialConfiguration(
createdAt: Instant
) {
def scope: String = configurationId

def withTruncatedTimestamp(unit: ChronoUnit = ChronoUnit.MICROS): CredentialConfiguration = copy(
createdAt = createdAt.truncatedTo(unit),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ package org.hyperledger.identus.pollux.core.model.oid4vci
import java.net.URL
import java.time.Instant
import java.util.UUID
import java.time.temporal.ChronoUnit

case class CredentialIssuer(id: UUID, authorizationServer: URL, createdAt: Instant, updatedAt: Instant)
case class CredentialIssuer(id: UUID, authorizationServer: URL, createdAt: Instant, updatedAt: Instant) {
def withTruncatedTimestamp(unit: ChronoUnit = ChronoUnit.MICROS): CredentialIssuer = copy(
createdAt = createdAt.truncatedTo(unit),
updatedAt = updatedAt.truncatedTo(unit),
)
}

object CredentialIssuer {
def apply(authorizationServer: URL): CredentialIssuer = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
package org.hyperledger.identus.pollux.core.repository

import org.hyperledger.identus.pollux.core.model.CredentialFormat
import org.hyperledger.identus.pollux.core.model.oid4vci.CredentialConfiguration
import org.hyperledger.identus.pollux.core.model.oid4vci.CredentialIssuer
import org.hyperledger.identus.shared.db.Errors.UnexpectedAffectedRow
import org.hyperledger.identus.shared.models.WalletAccessContext
import org.hyperledger.identus.shared.models.WalletId
import zio.test.*
import zio.test.Assertion.*
import zio.{ZIO, ZLayer}

import java.net.URI
import java.time.Instant

object OID4VCIIssuerMetadataRepositorySpecSuite {

private val credConfig = CredentialConfiguration(
configurationId = "DrivingLicense",
format = CredentialFormat.JWT,
schemaId = URI.create("http://example.com/schema"),
createdAt = Instant.now
).withTruncatedTimestamp()

private def initMultiWalletIssuers = {
val walletId1 = WalletId.random
val walletId2 = WalletId.random
val wallet1 = ZLayer.succeed(WalletAccessContext(walletId1))
val wallet2 = ZLayer.succeed(WalletAccessContext(walletId2))
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
authServer2 = URI.create("http://example-2.com").toURL()
issuer1 = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
issuer2 = CredentialIssuer(authorizationServer = authServer2).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer1).provide(wallet1)
_ <- repo.createIssuer(issuer2).provide(wallet2)
} yield (issuer1, wallet1, issuer2, wallet2)
}

val testSuite = suite("CRUD operations")(
test("find non-existing credential issuers return None") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
issuerId <- ZIO.randomWith(_.nextUUID)
maybeIssuer <- repo.findIssuerById(issuerId)
} yield assert(maybeIssuer)(isNone)
},
test("create credential issuers successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
authServer2 = URI.create("http://example-2.com").toURL()
issuer1 = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
issuer2 = CredentialIssuer(authorizationServer = authServer2).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer1)
_ <- repo.createIssuer(issuer2)
maybeIssuer1 <- repo.findIssuerById(issuer1.id)
maybeIssuer2 <- repo.findIssuerById(issuer2.id)
} yield assert(maybeIssuer1)(isSome(equalTo(issuer1))) &&
assert(maybeIssuer2)(isSome(equalTo(issuer2)))
},
test("create credential issuers with same id should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
issuer1 = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer1)
exit <- repo.createIssuer(issuer1).exit
} yield assert(exit)(dies(anything))
},
test("delete credential issuer successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.deleteIssuer(issuer.id)
maybeIssuer <- repo.findIssuerById(issuer.id)
} yield assert(maybeIssuer)(isNone)
},
test("delete non-existing credential issuer should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
exit <- repo.deleteIssuer(issuer.id).exit
} yield assert(exit)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
test("update credential issuer successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
authServer2 = URI.create("http://example-2.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.updateIssuer(issuer.id, authorizationServer = Some(authServer2))
updatedIssuer <- repo.findIssuerById(issuer.id).some
} yield assert(updatedIssuer.id)(equalTo(issuer.id)) &&
assert(updatedIssuer.authorizationServer)(equalTo(authServer2)) &&
assert(updatedIssuer.updatedAt)(not(equalTo(issuer.createdAt)))
},
test("update credential issuer with empty patch successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
authServer2 = URI.create("http://example-2.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.updateIssuer(issuer.id) // empty patch
updatedIssuer <- repo.findIssuerById(issuer.id).some
} yield assert(updatedIssuer.id)(equalTo(issuer.id)) &&
assert(updatedIssuer.authorizationServer)(equalTo(issuer.authorizationServer)) &&
assert(updatedIssuer.createdAt)(equalTo(issuer.createdAt))
},
test("update non-existing credential issuer should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
issuerId <- ZIO.randomWith(_.nextUUID)
authServer = URI.create("http://example-1.com").toURL()
exit <- repo.updateIssuer(issuerId, authorizationServer = Some(authServer)).exit
} yield assert(exit)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
test("create credential configuration successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig)
maybeCredConfig <- repo.findCredentialConfigurationById(issuer.id, credConfig.configurationId)
} yield assert(maybeCredConfig)(isSome(equalTo(credConfig)))
},
test("create credential configuration with same id should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig)
exit <- repo.createCredentialConfiguration(issuer.id, credConfig).exit
} yield assert(exit)(dies(anything))
},
test("create credential configuration with same id for different issuer successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer1 = URI.create("http://example-1.com").toURL()
authServer2 = URI.create("http://example-2.com").toURL()
issuer1 = CredentialIssuer(authorizationServer = authServer1).withTruncatedTimestamp()
issuer2 = CredentialIssuer(authorizationServer = authServer2).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer1)
_ <- repo.createIssuer(issuer2)
_ <- repo.createCredentialConfiguration(issuer1.id, credConfig)
_ <- repo.createCredentialConfiguration(issuer2.id, credConfig)
maybeCredConfig1 <- repo.findCredentialConfigurationById(issuer1.id, credConfig.configurationId)
maybeCredConfig2 <- repo.findCredentialConfigurationById(issuer2.id, credConfig.configurationId)
} yield assert(maybeCredConfig1)(isSome(equalTo(credConfig))) &&
assert(maybeCredConfig2)(isSome(equalTo(credConfig)))
},
test("create credential configuration for non-existing issuer should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
issuerId <- ZIO.randomWith(_.nextUUID)
exit <- repo.createCredentialConfiguration(issuerId, credConfig).exit
} yield assert(exit)(dies(anything))
},
test("list credential configurations successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
credConfig1 = credConfig.copy(configurationId = "DrivingLicense")
credConfig2 = credConfig.copy(configurationId = "UniversityDegree")
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig1)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig2)
credConfigs <- repo.findCredentialConfigurationsByIssuer(issuer.id)
} yield assert(credConfigs)(hasSameElements(Seq(credConfig1, credConfig2)))
},
test("find and list return empty result for non-existing configurations") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
maybeCredConfig <- repo.findCredentialConfigurationById(issuer.id, credConfig.configurationId)
credConfigs <- repo.findCredentialConfigurationsByIssuer(issuer.id)
} yield assert(maybeCredConfig)(isNone) &&
assert(credConfigs)(isEmpty)
},
test("delete credential configuration successfully") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig)
maybeCredConfig1 <- repo.findCredentialConfigurationById(issuer.id, credConfig.configurationId)
_ <- repo.deleteCredentialConfiguration(issuer.id, credConfig.configurationId)
maybeCredConfig2 <- repo.findCredentialConfigurationById(issuer.id, credConfig.configurationId)
} yield assert(maybeCredConfig1)(isSome(equalTo(credConfig))) &&
assert(maybeCredConfig2)(isNone)
},
test("delete non-existing creential configuration should fail") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
randomId <- ZIO.randomWith(_.nextUUID)
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig)
exit1 <- repo.deleteCredentialConfiguration(issuer.id, "ExampleLicense").exit
exit2 <- repo.deleteCredentialConfiguration(randomId, "ExampleLicense").exit
} yield assert(exit1)(dies(isSubtype[UnexpectedAffectedRow](anything))) &&
assert(exit2)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
test("delete issuer also delete credential configuration") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
authServer = URI.create("http://example-1.com").toURL()
issuer = CredentialIssuer(authorizationServer = authServer).withTruncatedTimestamp()
_ <- repo.createIssuer(issuer)
_ <- repo.createCredentialConfiguration(issuer.id, credConfig)
_ <- repo.deleteIssuer(issuer.id)
maybeCredConfig <- repo.findCredentialConfigurationById(issuer.id, credConfig.configurationId)
} yield assert(maybeCredConfig)(isNone)
}
).provideSomeLayer(ZLayer.succeed(WalletAccessContext(WalletId.random)))

val multitenantTestSuite = suite("multi-tenant CRUD operation")(
test("list only issuers inside wallet") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
init <- initMultiWalletIssuers
(issuer1, wallet1, issuer2, wallet2) = init
issuers1 <- repo.findWalletIssuers.provide(wallet1)
issuers2 <- repo.findWalletIssuers.provide(wallet2)
} yield assert(issuers1)(hasSameElements(Seq(issuer1))) &&
assert(issuers2)(hasSameElements(Seq(issuer2)))
},
test("update issuer across wallet is not allowed") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
init <- initMultiWalletIssuers
(issuer1, wallet1, issuer2, wallet2) = init
exit <- repo.updateIssuer(issuer1.id).provide(wallet2).exit
} yield assert(exit)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
test("delete issuer across wallet is not allowed") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
init <- initMultiWalletIssuers
(issuer1, wallet1, issuer2, wallet2) = init
exit <- repo.deleteIssuer(issuer1.id).provide(wallet2).exit
} yield assert(exit)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
test("create credential configuration across wallet is not allowed") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
init <- initMultiWalletIssuers
(issuer1, wallet1, issuer2, wallet2) = init
exit <- repo.createCredentialConfiguration(issuer1.id, credConfig).provide(wallet2).exit
} yield assert(exit)(dies(anything))
},
test("delete credential configuration across wallet is not allowed") {
for {
repo <- ZIO.service[OID4VCIIssuerMetadataRepository]
init <- initMultiWalletIssuers
(issuer1, wallet1, issuer2, wallet2) = init
exit <- repo.deleteCredentialConfiguration(issuer1.id, credConfig.configurationId).provide(wallet2).exit
} yield assert(exit)(dies(isSubtype[UnexpectedAffectedRow](anything)))
},
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.hyperledger.identus.pollux.sql.repository

import org.hyperledger.identus.pollux.core.repository.OID4VCIIssuerMetadataRepository
import org.hyperledger.identus.pollux.core.repository.OID4VCIIssuerMetadataRepositorySpecSuite
import org.hyperledger.identus.sharedtest.containers.PostgresTestContainerSupport
import org.hyperledger.identus.test.container.MigrationAspects
import zio.*
import zio.test.*

object JdbcOID4VCIIssuerMetadataRepositorySpec extends ZIOSpecDefault, PostgresTestContainerSupport {

private val migration = MigrationAspects.migrateEach(
schema = "public",
paths = "classpath:sql/pollux"
)

private val testEnvironemtnLayer = ZLayer.make[OID4VCIIssuerMetadataRepository](
JdbcOID4VCIIssuerMetadataRepository.layer,
contextAwareTransactorLayer,
systemTransactorLayer
)

override def spec =
(suite("JdbcOID4VCIIssuerMetadataRepository")(
OID4VCIIssuerMetadataRepositorySpecSuite.testSuite,
OID4VCIIssuerMetadataRepositorySpecSuite.multitenantTestSuite,
) @@ migration).provide(
Runtime.removeDefaultLoggers,
testEnvironemtnLayer,
pgContainerLayer,
)
}

0 comments on commit 3596a50

Please sign in to comment.