Skip to content

Commit

Permalink
test(castor): add more validation tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Pat Losoponkul committed Feb 2, 2023
1 parent 68893d8 commit 175f8e5
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ private object CreateOperationValidator extends BaseOperationValidator {
private def validateServiceNonEmptyEndpoints(
operation: PrismDIDOperation.Create
): Either[DIDOperationError, Unit] = {
val serviceWithEmptyEndpoints = operation.services.filter(_.serviceEndpoint.isEmpty)
val serviceWithEmptyEndpoints = operation.services.filter(_.serviceEndpoint.isEmpty).map(_.id)
if (serviceWithEmptyEndpoints.isEmpty) Right(())
else
Left(
DIDOperationError.InvalidArgument(
s"new service must not have empty serviceEndpoint: ${serviceWithEmptyEndpoints.mkString("[", ", ", "]")}"
s"service must not have empty serviceEndpoint: ${serviceWithEmptyEndpoints.mkString("[", ", ", "]")}"
)
)
}
Expand All @@ -90,6 +90,7 @@ private object UpdateOperationValidator extends BaseOperationValidator {
_ <- validatePreviousOperationHash(operation, _.previousOperationHash)
_ <- validateNonEmptyUpdateAction(operation)
_ <- validateUpdateServiceNonEmpty(operation)
_ <- validateAddServiceNonEmptyEndpoint(operation)
} yield ()
}

Expand All @@ -113,6 +114,22 @@ private object UpdateOperationValidator extends BaseOperationValidator {
)
}

private def validateAddServiceNonEmptyEndpoint(
operation: PrismDIDOperation.Update
): Either[DIDOperationError, Unit] = {
val serviceWithEmptyEndpoints = operation.actions
.collect { case UpdateDIDAction.AddService(s) => s }
.filter(_.serviceEndpoint.isEmpty)
.map(_.id)
if (serviceWithEmptyEndpoints.isEmpty) Right(())
else
Left(
DIDOperationError.InvalidArgument(
s"service must not have empty serviceEndpoint: ${serviceWithEmptyEndpoints.mkString("[", ", ", "]")}"
)
)
}

private def extractKeyIds(operation: PrismDIDOperation.Update): Seq[String] = operation.actions.flatMap {
case UpdateDIDAction.AddKey(publicKey) => Some(publicKey.id)
case UpdateDIDAction.AddInternalKey(publicKey) => Some(publicKey.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
y = Base64UrlString.fromStringUnsafe("00")
)

private def invalidArgumentContainsString(text: String): Assertion[Either[Any, Any]] = isLeft(
isSubtype[DIDOperationError.InvalidArgument](hasField("msg", _.msg, containsString(text)))
)

private val createOperationValidationSpec = {
def createPrismDIDOperation(
publicKeys: Seq[PublicKey] = Nil,
Expand Down Expand Up @@ -90,11 +94,7 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
)
val op = createPrismDIDOperation(publicKeys = publicKeys, internalKeys = internalKeys)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("id for public-keys is not unique"))
)
)
invalidArgumentContainsString("id for public-keys is not unique")
)
},
test("reject CreateOperation on too many service access") {
Expand All @@ -120,11 +120,7 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
)
val op = createPrismDIDOperation(services = services)
assert(DIDOperationValidator(Config(15, 15)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("id for services is not unique"))
)
)
invalidArgumentContainsString("id for services is not unique")
)
},
test("reject CreateOperation on invalid key-id") {
Expand All @@ -137,11 +133,7 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
)
val op = createPrismDIDOperation(publicKeys = publicKeys)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("public key id is invalid: [key 1, key 2]"))
)
)
invalidArgumentContainsString("public key id is invalid: [key 1, key 2]")
)
},
test("reject CreateOperation on invalid service-id") {
Expand All @@ -154,33 +146,56 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
)
val op = createPrismDIDOperation(services = services)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("service id is invalid: [service 1, service 2]"))
)
)
invalidArgumentContainsString("service id is invalid: [service 1, service 2]")
)
},
test("reject CreateOperation when master does not exist") {
test("reject CreateOperation when master key does not exist") {
val op = createPrismDIDOperation(internalKeys = Nil)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("operation must contain at least 1 master key"))
invalidArgumentContainsString("operation must contain at least 1 master key")
)
},
test("reject CreateOperation when service endpoint is empty") {
val op = createPrismDIDOperation(services =
Seq(
Service(
id = "service-0",
`type` = ServiceType.MediatorService,
serviceEndpoint = Nil
)
)
)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("service must not have empty serviceEndpoint")
)
},
test("reject CreateOperation when service URL is not normalized") {
val op = createPrismDIDOperation(services =
Seq(
Service(
id = "service-0",
`type` = ServiceType.MediatorService,
serviceEndpoint = Seq(
URI.create("http://example.com/login/../login")
)
)
)
)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("serviceEndpoint URIs must be normalized")
)
}
)
}

private val updateOperationValidationSpec = {
def updatePrismDIDOperation(
actions: Seq[UpdateDIDAction] = Nil
actions: Seq[UpdateDIDAction] = Nil,
previousOperationHash: ArraySeq[Byte] = ArraySeq.fill(32)(0)
) =
PrismDIDOperation.Update(
did = PrismDID.buildCanonicalFromSuffix("0" * 64).toOption.get,
ArraySeq.fill(32)(0),
PrismDID.buildCanonicalFromSuffix("0" * 64).toOption.get,
previousOperationHash,
actions
)

Expand Down Expand Up @@ -265,11 +280,7 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
val action2 = UpdateDIDAction.RemoveKey(id = "key 2")
val op = updatePrismDIDOperation(Seq(action1, action2))
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("public key id is invalid: [key 1, key 2]"))
)
)
invalidArgumentContainsString("public key id is invalid: [key 1, key 2]")
)
},
test("reject UpdateOperation on invalid service-id") {
Expand All @@ -283,32 +294,54 @@ object DIDOperationValidatorSpec extends ZIOSpecDefault {
val action2 = UpdateDIDAction.RemoveService(id = "service 2")
val op = updatePrismDIDOperation(Seq(action1, action2))
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("service id is invalid: [service 1, service 2]"))
)
)
invalidArgumentContainsString("service id is invalid: [service 1, service 2]")
)
},
test("reject UpdateOperation on invalid previousOperationHash") {
val op = updatePrismDIDOperation(previousOperationHash = ArraySeq.empty)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("previousOperationHash must have a size of")
)
},
test("reject UpdateOperation on empty update action") {
val op = updatePrismDIDOperation(Nil)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("operation must contain at least 1 update action"))
)
)
invalidArgumentContainsString("operation must contain at least 1 update action")
)
},
test("reject UpdateOperation on UpdateService action empty") {
val op = updatePrismDIDOperation(Seq(UpdateDIDAction.UpdateService("service0", None, Nil)))
test("reject UpdateOperation when action AddService serviceEndpoint is empty") {
val op = updatePrismDIDOperation(
Seq(UpdateDIDAction.AddService(Service("service-1", ServiceType.MediatorService, Nil)))
)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
isLeft(
isSubtype[DIDOperationError.InvalidArgument](
hasField("msg", _.msg, containsString("must not have both 'type' and 'serviceEndpoints' empty"))
invalidArgumentContainsString("service must not have empty serviceEndpoint")
)
},
test("reject UpdateOperation when action AddService serviceEndpoint is not normalized") {
val op = updatePrismDIDOperation(
Seq(
UpdateDIDAction.AddService(
Service("service-1", ServiceType.MediatorService, Seq(URI.create("http://example.com/login/../login")))
)
)
)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("serviceEndpoint URIs must be normalized")
)
},
test("reject updateOperation when action UpdateService serviceEndpoint is not normalized") {
val op = updatePrismDIDOperation(
Seq(UpdateDIDAction.UpdateService("service-1", None, Seq(URI.create("http://example.com/login/../login"))))
)
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("serviceEndpoint URIs must be normalized")
)
},
test("reject UpdateOperation when action UpdateService have both type and serviceEndpoint empty") {
val op = updatePrismDIDOperation(Seq(UpdateDIDAction.UpdateService("service-1", None, Nil)))
assert(DIDOperationValidator(Config(50, 50)).validate(op))(
invalidArgumentContainsString("must not have both 'type' and 'serviceEndpoints' empty")
)
}
)
}
Expand Down

0 comments on commit 175f8e5

Please sign in to comment.