From 813c5612fcf780f121beaff39efb3b70715bd4f7 Mon Sep 17 00:00:00 2001 From: jameshall1999 <67314983+jameshall1999@users.noreply.github.com> Date: Wed, 3 Mar 2021 12:55:59 +0000 Subject: [PATCH] APID-85: Store records with status insead of _type as discriminator --- .../models/OutboundSoapMessage.scala | 33 ++++++++++++------- .../repositories/MongoFormatter.scala | 10 +++++- .../OutboundMessageRepository.scala | 4 +-- .../OutboundMessageRepositoryISpec.scala | 24 +++++++++++++- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/app/uk/gov/hmrc/apiplatformoutboundsoap/models/OutboundSoapMessage.scala b/app/uk/gov/hmrc/apiplatformoutboundsoap/models/OutboundSoapMessage.scala index 09db38b..200b194 100644 --- a/app/uk/gov/hmrc/apiplatformoutboundsoap/models/OutboundSoapMessage.scala +++ b/app/uk/gov/hmrc/apiplatformoutboundsoap/models/OutboundSoapMessage.scala @@ -21,6 +21,7 @@ import org.joda.time.DateTime import java.util.UUID import scala.collection.immutable +import scala.reflect.classTag sealed trait OutboundSoapMessage { val globalId: UUID @@ -32,6 +33,22 @@ sealed trait OutboundSoapMessage { val ccnHttpStatus: Int } +object OutboundSoapMessage { + + def typeToStatus (fullyQualifiedName: String): SendingStatus = { + + if (fullyQualifiedName == classTag[SentOutboundSoapMessage].runtimeClass.getCanonicalName) { + SendingStatus.SENT + } else if (fullyQualifiedName == classTag[FailedOutboundSoapMessage].runtimeClass.getCanonicalName) { + SendingStatus.FAILED + } else if (fullyQualifiedName == classTag[RetryingOutboundSoapMessage].runtimeClass.getCanonicalName) { + SendingStatus.RETRYING + } else { + throw new IllegalArgumentException + } + } +} + case class SentOutboundSoapMessage(globalId: UUID, messageId: Option[String], soapMessage: String, @@ -63,23 +80,15 @@ case class RetryingOutboundSoapMessage(globalId: UUID, def toSent = SentOutboundSoapMessage(globalId, messageId, soapMessage, createDateTime, ccnHttpStatus, notificationUrl) } -sealed trait SendingStatus extends EnumEntry { - val soapMessageType: String -} +sealed trait SendingStatus extends EnumEntry object SendingStatus extends Enum[SendingStatus] with PlayJsonEnum[SendingStatus] { val values: immutable.IndexedSeq[SendingStatus] = findValues - case object SENT extends SendingStatus { - override val soapMessageType: String = "uk.gov.hmrc.apiplatformoutboundsoap.models.SentOutboundSoapMessage" - } + case object SENT extends SendingStatus - case object FAILED extends SendingStatus { - override val soapMessageType: String = "uk.gov.hmrc.apiplatformoutboundsoap.models.FailedOutboundSoapMessage" - } + case object FAILED extends SendingStatus - case object RETRYING extends SendingStatus { - override val soapMessageType: String = "uk.gov.hmrc.apiplatformoutboundsoap.models.RetryingOutboundSoapMessage" - } + case object RETRYING extends SendingStatus } diff --git a/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/MongoFormatter.scala b/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/MongoFormatter.scala index 61e90bf..1d05984 100644 --- a/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/MongoFormatter.scala +++ b/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/MongoFormatter.scala @@ -17,11 +17,19 @@ package uk.gov.hmrc.apiplatformoutboundsoap.repositories import org.joda.time.DateTime -import play.api.libs.json.{Format, Json, OFormat} +import play.api.libs.json.{Format, Json, JsonConfiguration, JsonNaming, OFormat} import uk.gov.hmrc.apiplatformoutboundsoap.models.{FailedOutboundSoapMessage, OutboundSoapMessage, RetryingOutboundSoapMessage, SentOutboundSoapMessage} import uk.gov.hmrc.mongo.json.ReactiveMongoFormats private[repositories] object MongoFormatter { + + implicit val cfg = JsonConfiguration( + discriminator = "status", + + typeNaming = JsonNaming { fullName => + OutboundSoapMessage.typeToStatus(fullName).entryName + }) + implicit val dateFormat: Format[DateTime] = ReactiveMongoFormats.dateTimeFormats implicit val outboundSoapMessageFormatter: OFormat[OutboundSoapMessage] = Json.format[OutboundSoapMessage] implicit val retryingSoapMessageFormatter: OFormat[RetryingOutboundSoapMessage] = Json.format[RetryingOutboundSoapMessage] diff --git a/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepository.scala b/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepository.scala index d0721bc..b6177bb 100644 --- a/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepository.scala +++ b/app/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepository.scala @@ -63,7 +63,7 @@ class OutboundMessageRepository @Inject()(mongoComponent: ReactiveMongoComponent import uk.gov.hmrc.apiplatformoutboundsoap.repositories.MongoFormatter.retryingSoapMessageFormatter collection - .find(Json.obj("_type" -> SendingStatus.RETRYING.soapMessageType, + .find(Json.obj("status" -> SendingStatus.RETRYING.entryName, "retryDateTime" -> Json.obj("$lte" -> now(UTC))), Option.empty[OutboundSoapMessage]) .sort(Json.obj("retryDateTime" -> 1)) .cursor[RetryingOutboundSoapMessage](ReadPreference.primaryPreferred) @@ -80,7 +80,7 @@ class OutboundMessageRepository @Inject()(mongoComponent: ReactiveMongoComponent def updateStatus(globalId: UUID, newStatus: SendingStatus): Future[Option[OutboundSoapMessage]] = { findAndUpdate(Json.obj("globalId" -> globalId), - Json.obj("$set" -> Json.obj("_type" -> newStatus.soapMessageType)), fetchNewObject = true) + Json.obj("$set" -> Json.obj("status" -> newStatus.entryName)), fetchNewObject = true) .map(_.result[OutboundSoapMessage]) } } diff --git a/it/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepositoryISpec.scala b/it/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepositoryISpec.scala index c3d22eb..1d245ff 100644 --- a/it/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepositoryISpec.scala +++ b/it/uk/gov/hmrc/apiplatformoutboundsoap/repositories/OutboundMessageRepositoryISpec.scala @@ -10,11 +10,14 @@ import org.scalatest.wordspec.AnyWordSpec import org.scalatestplus.play.guice.GuiceOneAppPerSuite import play.api.Application import play.api.inject.guice.GuiceApplicationBuilder +import play.api.libs.json.{JsObject, Json} +import play.api.test.Helpers.contentAsJson import reactivemongo.api.ReadPreference import reactivemongo.bson.BSONLong import reactivemongo.core.errors.DatabaseException import uk.gov.hmrc.apiplatformoutboundsoap.models.{FailedOutboundSoapMessage, RetryingOutboundSoapMessage, SendingStatus, SentOutboundSoapMessage} import uk.gov.hmrc.mongo.RepositoryPreparation +import reactivemongo.play.json.ImplicitBSONHandlers.JsObjectDocumentWriter import java.util.UUID.randomUUID @@ -36,13 +39,18 @@ class OutboundMessageRepositoryISpec extends AnyWordSpec with Matchers with Repo } val retryingMessage = RetryingOutboundSoapMessage(randomUUID, Some("MessageId-A1"), "payload", DateTime.now(UTC), DateTime.now(UTC), ccnHttpStatus) - val sentMessage = SentOutboundSoapMessage(randomUUID, Some("MessageId-A1"), "payload", DateTime.now(UTC), ccnHttpStatus) + val sentMessage = SentOutboundSoapMessage(randomUUID, Some("MessageId-A2"), "payload", DateTime.now(UTC), ccnHttpStatus) + val failedMessage = FailedOutboundSoapMessage(randomUUID, Some("MessageId-A3"), "payload", DateTime.now(UTC), ccnHttpStatus) "persist" should { "insert a retrying message when it does not exist" in { await(repo.persist(retryingMessage)) val fetchedRecords = await(repo.findAll(ReadPreference.primaryPreferred)) + val Some(jsonRecord) = await(repo.collection.find(Json.obj()).one[JsObject]) + (jsonRecord \ "status").as[String] shouldBe "RETRYING" + + fetchedRecords.size shouldBe 1 fetchedRecords.head shouldBe retryingMessage } @@ -51,10 +59,24 @@ class OutboundMessageRepositoryISpec extends AnyWordSpec with Matchers with Repo await(repo.persist(sentMessage)) val fetchedRecords = await(repo.findAll(ReadPreference.primaryPreferred)) + val Some(jsonRecord) = await(repo.collection.find(Json.obj()).one[JsObject]) + (jsonRecord \ "status").as[String] shouldBe "SENT" + fetchedRecords.size shouldBe 1 fetchedRecords.head shouldBe sentMessage } + "insert a failed message when it does not exist" in { + await(repo.persist(failedMessage)) + + val fetchedRecords = await(repo.findAll(ReadPreference.primaryPreferred)) + val Some(jsonRecord) = await(repo.collection.find(Json.obj()).one[JsObject]) + (jsonRecord \ "status").as[String] shouldBe "FAILED" + + fetchedRecords.size shouldBe 1 + fetchedRecords.head shouldBe failedMessage + } + "message is persisted with TTL" in { await(repo.persist(sentMessage))