diff --git a/app/uk/gov/hmrc/apisubscriptionfields/connector/JsonFormatters.scala b/app/uk/gov/hmrc/apisubscriptionfields/connector/JsonFormatters.scala
index f6d728e..02f31c4 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/connector/JsonFormatters.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/connector/JsonFormatters.scala
@@ -17,12 +17,10 @@
package uk.gov.hmrc.apisubscriptionfields.connector
import play.api.libs.json._
-import uk.gov.hmrc.apiplatform.modules.common.domain.models._
import uk.gov.hmrc.apisubscriptionfields.model.{BoxId, SubscriptionFieldsId}
trait JsonFormatters {
- implicit val clientIdJF: Format[ClientId] = Json.valueFormat[ClientId]
implicit val boxIdJF: Format[BoxId] = Json.valueFormat[BoxId]
implicit val subscriptionFieldsIdJF: Format[SubscriptionFieldsId] = Json.valueFormat[SubscriptionFieldsId]
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnector.scala b/app/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnector.scala
index 95808f7..64788f0 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnector.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnector.scala
@@ -60,13 +60,15 @@ class PushPullNotificationServiceConnector @Inject() (http: HttpClient, appConfi
}
}
- def updateCallBackUrl(clientId: ClientId, boxId: BoxId, callbackUrl: FieldValue)(implicit hc: HeaderCarrier): Future[PPNSCallBackUrlValidationResponse] = {
+ def updateCallBackUrl(clientId: ClientId, boxId: BoxId, callbackUrl: FieldValue)(implicit hc: HeaderCarrier): Future[Either[String, Unit]] = {
val payload = UpdateCallBackUrlRequest(clientId, callbackUrl)
http
.PUT[UpdateCallBackUrlRequest, UpdateCallBackUrlResponse](s"$externalServiceUri/box/${boxId.value.toString}/callback", payload)
.map(response =>
- if (response.successful) PPNSCallBackUrlSuccessResponse
- else response.errorMessage.fold(PPNSCallBackUrlFailedResponse("Unknown Error"))(PPNSCallBackUrlFailedResponse)
+ if (response.successful)
+ Right(())
+ else
+ Left(response.errorMessage.getOrElse("Unknown Error"))
)
.recover { case NonFatal(e) =>
throw new RuntimeException(s"Unexpected response from $externalServiceUri: ${e.getMessage}")
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/controller/SubscriptionFieldsController.scala b/app/uk/gov/hmrc/apisubscriptionfields/controller/SubscriptionFieldsController.scala
index 622a6fd..1643033 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/controller/SubscriptionFieldsController.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/controller/SubscriptionFieldsController.scala
@@ -92,11 +92,9 @@ class SubscriptionFieldsController @Inject() (cc: ControllerComponents, service:
.upsert(clientId, apiContext, apiVersionNbr, payload.fields)
.map(_ match {
case NotFoundSubsFieldsUpsertResponse => BadRequest(Json.toJson("reason" -> "field definitions not found")) // TODO
- case FailedValidationSubsFieldsUpsertResponse(fieldErrorMessages) =>
- BadRequest(Json.toJson(fieldErrorMessages))
+ case FailedValidationSubsFieldsUpsertResponse(fieldErrorMessages) => BadRequest(Json.toJson(fieldErrorMessages))
case SuccessfulSubsFieldsUpsertResponse(response, true) => Created(Json.toJson(response))
- case SuccessfulSubsFieldsUpsertResponse(response, false) =>
- Ok(Json.toJson(response))
+ case SuccessfulSubsFieldsUpsertResponse(response, false) => Ok(Json.toJson(response))
})
.recover(recovery)
}
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/Topics.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/BoxId.scala
similarity index 100%
rename from app/uk/gov/hmrc/apisubscriptionfields/model/Topics.scala
rename to app/uk/gov/hmrc/apisubscriptionfields/model/BoxId.scala
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala
index 52f3ba4..35edeb6 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala
@@ -35,10 +35,6 @@ sealed trait SubsFieldValidationResponse
case object ValidSubsFieldValidationResponse extends SubsFieldValidationResponse
case class InvalidSubsFieldValidationResponse(errorResponses: Map[FieldName, String]) extends SubsFieldValidationResponse
-sealed trait PPNSCallBackUrlValidationResponse
-case object PPNSCallBackUrlSuccessResponse extends PPNSCallBackUrlValidationResponse
-case class PPNSCallBackUrlFailedResponse(errorMsg: String) extends PPNSCallBackUrlValidationResponse
-
sealed trait ErrorCode
object ErrorCode {
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationService.scala b/app/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationService.scala
index 7c70345..238d1f4 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationService.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationService.scala
@@ -17,39 +17,28 @@
package uk.gov.hmrc.apisubscriptionfields.service
import javax.inject.{Inject, Singleton}
-import scala.concurrent.{ExecutionContext, Future}
+import scala.concurrent.Future
import uk.gov.hmrc.apiplatform.modules.common.domain.models._
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.apisubscriptionfields.connector.PushPullNotificationServiceConnector
-import uk.gov.hmrc.apisubscriptionfields.model.Types.FieldValue
-import uk.gov.hmrc.apisubscriptionfields.model.{FieldDefinition, _}
+import uk.gov.hmrc.apisubscriptionfields.model.BoxId
+import uk.gov.hmrc.apisubscriptionfields.model.Types.{FieldName, FieldValue}
@Singleton
-class PushPullNotificationService @Inject() (ppnsConnector: PushPullNotificationServiceConnector)(implicit ec: ExecutionContext) {
+class PushPullNotificationService @Inject() (ppnsConnector: PushPullNotificationServiceConnector) {
- def makeBoxName(apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fieldDefinition: FieldDefinition): String = {
+ def makeBoxName(apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fieldName: FieldName): String = {
val separator = "##"
- s"${apiContext.value}${separator}${apiVersionNbr.value}${separator}${fieldDefinition.name.value}"
+ s"${apiContext.value}${separator}${apiVersionNbr.value}${separator}${fieldName.value}"
}
- def subscribeToPPNS(
- clientId: ClientId,
- apiContext: ApiContext,
- apiVersionNbr: ApiVersionNbr,
- oFieldValue: Option[FieldValue],
- fieldDefinition: FieldDefinition
- )(implicit
- hc: HeaderCarrier
- ): Future[PPNSCallBackUrlValidationResponse] = {
- for {
- boxId <- ppnsConnector.ensureBoxIsCreated(makeBoxName(apiContext, apiVersionNbr, fieldDefinition), clientId)
- result <- oFieldValue match {
- case Some(value) => ppnsConnector.updateCallBackUrl(clientId, boxId, value)
- case None => Future.successful(PPNSCallBackUrlSuccessResponse)
- }
- } yield result
+ def ensureBoxIsCreated(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fieldName: FieldName)(implicit hc: HeaderCarrier): Future[BoxId] = {
+ ppnsConnector.ensureBoxIsCreated(makeBoxName(apiContext, apiVersionNbr, fieldName), clientId)
}
+ def updateCallbackUrl(clientId: ClientId, boxId: BoxId, fieldValue: FieldValue)(implicit hc: HeaderCarrier): Future[Either[String, Unit]] = {
+ ppnsConnector.updateCallBackUrl(clientId, boxId, fieldValue)
+ }
}
diff --git a/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala b/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala
index 1d1203e..f3d6a16 100644
--- a/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala
+++ b/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala
@@ -22,8 +22,10 @@ import scala.concurrent.{ExecutionContext, Future}
import cats.data.NonEmptyList
import cats.data.{NonEmptyList => NEL}
+import cats.implicits._
import uk.gov.hmrc.apiplatform.modules.common.domain.models._
+import uk.gov.hmrc.apiplatform.modules.common.services.EitherTHelper
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.apisubscriptionfields.model.Types._
@@ -32,89 +34,116 @@ import uk.gov.hmrc.apisubscriptionfields.repository.SubscriptionFieldsRepository
@Singleton
class SubscriptionFieldsService @Inject() (
- repository: SubscriptionFieldsRepository,
+ subscriptionFieldsRepository: SubscriptionFieldsRepository,
apiFieldDefinitionsService: ApiFieldDefinitionsService,
pushPullNotificationService: PushPullNotificationService
)(implicit ec: ExecutionContext
) {
- private def validate(fields: Fields, fieldDefinitions: NonEmptyList[FieldDefinition]): SubsFieldValidationResponse = {
- SubscriptionFieldsService.validateAgainstValidationRules(fieldDefinitions, fields) ++ SubscriptionFieldsService.validateFieldNamesAreDefined(fieldDefinitions, fields) match {
- case FieldErrorMap.empty => ValidSubsFieldValidationResponse
- case errs: FieldErrorMap => InvalidSubsFieldValidationResponse(errorResponses = errs)
+ def upsert(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, newFields: Fields)(implicit hc: HeaderCarrier): Future[SubsFieldsUpsertResponse] = {
+ def findPpnsField(fieldDefinitions: NEL[FieldDefinition]): Option[FieldDefinition] = fieldDefinitions.find(_.`type` == FieldDefinitionType.PPNS_FIELD)
+
+ def handleAnyPpnsSubscriptionRequired(
+ clientId: ClientId,
+ apiContext: ApiContext,
+ apiVersionNbr: ApiVersionNbr,
+ fieldDefinitions: NEL[FieldDefinition],
+ existingFields: Option[SubscriptionFields]
+ )(implicit
+ hc: HeaderCarrier
+ ): Future[Either[String, Unit]] = {
+
+ findPpnsField(fieldDefinitions) match {
+ case Some(fieldDefinition) =>
+ val fieldName = fieldDefinition.name
+ newFields.get(fieldName) match {
+ case Some(newFieldValue) =>
+ for {
+ boxId <- pushPullNotificationService.ensureBoxIsCreated(clientId, apiContext, apiVersionNbr, fieldName)
+ fieldValueHasNotChanged = existingFields.map(_.fields.get(fieldName).contains(newFieldValue)).getOrElse(false)
+ result <- if (fieldValueHasNotChanged) successful(Right(()))
+ else pushPullNotificationService.updateCallbackUrl(clientId, boxId, newFieldValue)
+ } yield result
+ case None => successful(Right(()))
+ }
+ case None => successful(Right(()))
+ }
}
- }
- private def upsertSubscriptionFields(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fields: Fields): Future[SuccessfulSubsFieldsUpsertResponse] = {
- repository
- .saveAtomic(clientId, apiContext, apiVersionNbr, fields)
- .map(result => SuccessfulSubsFieldsUpsertResponse(result._1, result._2))
- }
+ def validateFields(fields: Fields, fieldDefinitions: NonEmptyList[FieldDefinition]): Either[FieldErrorMap, Unit] = {
+ SubscriptionFieldsService.validateAgainstValidationRules(fieldDefinitions, fields) ++ SubscriptionFieldsService.validateFieldNamesAreDefined(fieldDefinitions, fields) match {
+ case FieldErrorMap.empty => Right(())
+ case errs: FieldErrorMap => Left(errs)
+ }
+ }
+
+ def translateValidateError(fieldErrorMessages: FieldErrorMap) = FailedValidationSubsFieldsUpsertResponse(fieldErrorMessages)
- def handlePPNS(
- clientId: ClientId,
- apiContext: ApiContext,
- apiVersionNbr: ApiVersionNbr,
- fieldDefinitions: NEL[FieldDefinition],
- fields: Fields
- )(implicit
- hc: HeaderCarrier
- ): Future[SubsFieldsUpsertResponse] = {
- val ppnsFieldDefinition: Option[FieldDefinition] = fieldDefinitions.find(_.`type` == FieldDefinitionType.PPNS_FIELD)
-
- ppnsFieldDefinition match {
- case Some(fieldDefinition) =>
- val oFieldValue: Option[FieldValue] = fields.get(fieldDefinition.name)
- pushPullNotificationService.subscribeToPPNS(clientId, apiContext, apiVersionNbr, oFieldValue, fieldDefinition).flatMap {
- case PPNSCallBackUrlSuccessResponse => upsertSubscriptionFields(clientId, apiContext, apiVersionNbr, fields)
- case PPNSCallBackUrlFailedResponse(error) => Future.successful(FailedValidationSubsFieldsUpsertResponse(Map(fieldDefinition.name -> error)))
- }
- case None => upsertSubscriptionFields(clientId, apiContext, apiVersionNbr, fields)
+ def translatePpnsError(fieldDefinitions: NEL[FieldDefinition])(error: String) = {
+ val fieldName = findPpnsField(fieldDefinitions).get.name
+ val fieldErrorMessages = Map(fieldName -> error)
+ FailedValidationSubsFieldsUpsertResponse(fieldErrorMessages)
}
- }
+ def upsertIfFieldsHaveChanged(anyExistingFields: Option[SubscriptionFields]) = {
+ def upsertSubscriptionFields(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fields: Fields): Future[SuccessfulSubsFieldsUpsertResponse] = {
+ subscriptionFieldsRepository
+ .saveAtomic(clientId, apiContext, apiVersionNbr, fields)
+ .map(result => SuccessfulSubsFieldsUpsertResponse(result._1, result._2))
+ }
+
+ anyExistingFields match {
+ case Some(existingFields) if (existingFields.fields == newFields) =>
+ successful(SuccessfulSubsFieldsUpsertResponse(existingFields, false))
+ case _ =>
+ upsertSubscriptionFields(clientId, apiContext, apiVersionNbr, newFields)
+ }
+ }
- def upsert(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr, fields: Fields)(implicit hc: HeaderCarrier): Future[SubsFieldsUpsertResponse] = {
- val foFieldDefinitions: Future[Option[NonEmptyList[FieldDefinition]]] =
- apiFieldDefinitionsService.get(apiContext, apiVersionNbr).map(_.map(_.fieldDefinitions))
-
- get(clientId, apiContext, apiVersionNbr).flatMap(_ match {
- case Some(sfields) if (sfields.fields == fields) => Future.successful(SuccessfulSubsFieldsUpsertResponse(sfields, false))
- case _ =>
- foFieldDefinitions.flatMap(_ match {
- case None => successful(NotFoundSubsFieldsUpsertResponse)
- case Some(fieldDefinitions) =>
- validate(fields, fieldDefinitions) match {
- case ValidSubsFieldValidationResponse => handlePPNS(clientId, apiContext, apiVersionNbr, fieldDefinitions, fields)
- case InvalidSubsFieldValidationResponse(fieldErrorMessages) => successful(FailedValidationSubsFieldsUpsertResponse(fieldErrorMessages))
- }
- })
- })
+ (for {
+ anyFieldDefinitions <- apiFieldDefinitionsService.get(apiContext, apiVersionNbr).map(_.map(_.fieldDefinitions))
+ anyExistingFields <- subscriptionFieldsRepository.fetch(clientId, apiContext, apiVersionNbr)
+ } yield (anyFieldDefinitions, anyExistingFields))
+ .flatMap(_ match {
+ case (None, Some(existingFields)) if (existingFields.fields == newFields) => successful(SuccessfulSubsFieldsUpsertResponse(existingFields, false))
+ case (None, _) => successful(NotFoundSubsFieldsUpsertResponse)
+ case (Some(fieldDefinitions), anyExistingFields) =>
+ val E = EitherTHelper.make[FailedValidationSubsFieldsUpsertResponse]
+ (
+ for {
+ _ <- E.fromEither(validateFields(newFields, fieldDefinitions).leftMap(translateValidateError))
+ _ <- E.fromEitherF(handleAnyPpnsSubscriptionRequired(clientId, apiContext, apiVersionNbr, fieldDefinitions, anyExistingFields)
+ .map(_.leftMap(translatePpnsError(fieldDefinitions))))
+ response <- E.liftF(upsertIfFieldsHaveChanged(anyExistingFields))
+ } yield response
+ )
+ .merge
+ })
}
def delete(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr): Future[Boolean] = {
- repository.delete(clientId, apiContext, apiVersionNbr)
+ subscriptionFieldsRepository.delete(clientId, apiContext, apiVersionNbr)
}
def delete(clientId: ClientId): Future[Boolean] = {
- repository.delete(clientId)
+ subscriptionFieldsRepository.delete(clientId)
}
def get(clientId: ClientId, apiContext: ApiContext, apiVersionNbr: ApiVersionNbr): Future[Option[SubscriptionFields]] = {
for {
- fetch <- repository.fetch(clientId, apiContext, apiVersionNbr)
+ fetch <- subscriptionFieldsRepository.fetch(clientId, apiContext, apiVersionNbr)
} yield fetch
}
def getBySubscriptionFieldId(subscriptionFieldsId: SubscriptionFieldsId): Future[Option[SubscriptionFields]] = {
for {
- fetch <- repository.fetchByFieldsId(subscriptionFieldsId)
+ fetch <- subscriptionFieldsRepository.fetchByFieldsId(subscriptionFieldsId)
} yield fetch
}
def getByClientId(clientId: ClientId): Future[Option[BulkSubscriptionFieldsResponse]] = {
(for {
- fields <- repository.fetchByClientId(clientId)
+ fields <- subscriptionFieldsRepository.fetchByClientId(clientId)
} yield fields)
.map {
case Nil => None
@@ -124,7 +153,7 @@ class SubscriptionFieldsService @Inject() (
def getAll: Future[BulkSubscriptionFieldsResponse] = {
(for {
- fields <- repository.fetchAll
+ fields <- subscriptionFieldsRepository.fetchAll
} yield fields)
.map(BulkSubscriptionFieldsResponse(_))
}
diff --git a/conf/application.conf b/conf/application.conf
index 008c744..5a4d6db 100644
--- a/conf/application.conf
+++ b/conf/application.conf
@@ -75,6 +75,8 @@ controllers {
# You can disable evolutions if needed
# evolutionplugin=disabled
+# Microservice specific config
+
mongo-async-driver {
akka {
loglevel = WARNING
diff --git a/conf/logback.xml b/conf/logback.xml
index 4aaecb2..7cf8b1f 100644
--- a/conf/logback.xml
+++ b/conf/logback.xml
@@ -45,7 +45,7 @@
-
+
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala b/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala
index 888a24f..07b7307 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala
@@ -80,7 +80,7 @@ trait FieldDefinitionTestData extends TestData {
FieldDefinition("password", "password", "this is your password", FieldDefinitionType.SECURE_TOKEN, "password", Some(FakeValidationForPassword))
final val FakeFieldDefinitionPPNSFields =
- FieldDefinition("callbackurl", "callbackurl", "please enter a callback url", FieldDefinitionType.PPNS_FIELD, "callbackurl", Some(FakeValidationForPPNS))
+ FieldDefinition(PPNSFieldFieldName, "Callback URL", "please enter a callback url", FieldDefinitionType.PPNS_FIELD, "callback", Some(FakeValidationForPPNS))
final val FakeApiFieldDefinitionssWithRegex = NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionAlphnumericField, FakeFieldDefinitionPassword))
final val FakeApiFieldDefinitionsPPNSWithRegex =
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala b/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala
index 8101ab3..41c4d10 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala
@@ -35,8 +35,10 @@ trait SubscriptionFieldsTestData extends FieldDefinitionTestData with Validation
final val SubscriptionFieldsMatchRegexValidation: Fields = Map(AlphanumericFieldName -> "ABC123ab", PasswordFieldName -> "Qw12@ert")
final val SubscriptionFieldsNonMatchRegexValidation: Fields = Map(AlphanumericFieldName -> "ABC123a", PasswordFieldName -> "Qw12@er")
+ final val PPNSFieldFieldValue: FieldValue = "https://www.mycallbackurl.com"
+
final val SubscriptionFieldsMatchRegexValidationPPNS: Fields =
- Map(AlphanumericFieldName -> "ABC123abc", PasswordFieldName -> "Qw12@erty", PPNSFieldFieldName -> "https://www.mycallbackurl.com")
+ Map(AlphanumericFieldName -> "ABC123abc", PasswordFieldName -> "Qw12@erty", PPNSFieldFieldName -> PPNSFieldFieldValue)
final val SubscriptionFieldsDoNotMatchRegexValidationPPNS: Fields = Map(AlphanumericFieldName -> "ABC123abc", PasswordFieldName -> "Qw12@erty", PPNSFieldFieldName -> "foo")
final val SubscriptionFieldsEmptyValueRegexValidationPPNS: Fields = Map(AlphanumericFieldName -> "ABC123abc", PasswordFieldName -> "Qw12@erty", PPNSFieldFieldName -> "")
final val SubscriptionFieldsDoNotMatchRegexValidation: Fields = Map(AlphanumericFieldName -> "ABC123abc=", PasswordFieldName -> "Qw12erty")
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/TestData.scala b/test/uk/gov/hmrc/apisubscriptionfields/TestData.scala
index 22c731c..c5f4885 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/TestData.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/TestData.scala
@@ -22,6 +22,8 @@ import play.api.http.HeaderNames.{ACCEPT, CONTENT_TYPE}
import play.api.http.MimeTypes
import uk.gov.hmrc.apiplatform.modules.common.domain.models._
+import uk.gov.hmrc.apisubscriptionfields.model.BoxId
+
trait TestData {
type EmulatedFailure = UnsupportedOperationException
@@ -42,6 +44,7 @@ trait TestData {
final val FakeClientId2 = ClientId(fakeRawClientId2)
+ final val FakeBoxId = BoxId(UUID.randomUUID())
}
object RequestHeaders {
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnectorSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnectorSpec.scala
index 1ab9418..0b79651 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnectorSpec.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/connector/PushPullNotificationServiceConnectorSpec.scala
@@ -173,8 +173,8 @@ class PushPullNotificationServiceConnectorSpec extends AsyncHmrcSpec with GuiceO
val path = s"/box/${boxId.value}/callback"
primeStub(path, requestBody, responseBody)
- val ret: PPNSCallBackUrlValidationResponse = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
- ret shouldBe PPNSCallBackUrlSuccessResponse
+ val ret = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
+ ret shouldBe Right(())
verifyPath(path)
}
@@ -187,8 +187,8 @@ class PushPullNotificationServiceConnectorSpec extends AsyncHmrcSpec with GuiceO
val path = s"/box/${boxId.value}/callback"
primeStub(path, requestBody, responseBody)
- val ret: PPNSCallBackUrlValidationResponse = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
- ret shouldBe PPNSCallBackUrlSuccessResponse
+ val ret = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
+ ret shouldBe Right(())
verifyPath(path)
}
@@ -201,8 +201,8 @@ class PushPullNotificationServiceConnectorSpec extends AsyncHmrcSpec with GuiceO
val path = s"/box/${boxId.value}/callback"
primeStub(path, requestBody, responseBody)
- val ret: PPNSCallBackUrlValidationResponse = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
- ret shouldBe PPNSCallBackUrlFailedResponse("some error")
+ val ret = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
+ ret shouldBe Left("some error")
verifyPath(path)
}
@@ -227,8 +227,8 @@ class PushPullNotificationServiceConnectorSpec extends AsyncHmrcSpec with GuiceO
val path = s"/box/${boxId.value}/callback"
primeStub(path, requestBody, responseBody)
- val ret: PPNSCallBackUrlValidationResponse = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
- ret shouldBe PPNSCallBackUrlFailedResponse("Unknown Error")
+ val ret = await(connector.updateCallBackUrl(clientId, boxId, callbackUrl))
+ ret shouldBe Left("Unknown Error")
verifyPath(path)
}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/mocks/ApiFieldDefinitionsServiceMockModule.scala b/test/uk/gov/hmrc/apisubscriptionfields/mocks/ApiFieldDefinitionsServiceMockModule.scala
new file mode 100644
index 0000000..daa3622
--- /dev/null
+++ b/test/uk/gov/hmrc/apisubscriptionfields/mocks/ApiFieldDefinitionsServiceMockModule.scala
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 HM Revenue & Customs
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package uk.gov.hmrc.apisubscriptionfields.mocks
+
+import scala.concurrent.Future.successful
+
+import org.mockito.{ArgumentMatchersSugar, MockitoSugar}
+
+import uk.gov.hmrc.apiplatform.modules.common.domain.models.{ApiContext, ApiVersionNbr}
+import uk.gov.hmrc.apiplatform.modules.common.utils.FixedClock
+
+import uk.gov.hmrc.apisubscriptionfields.model.ApiFieldDefinitions
+import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService
+
+trait ApiFieldDefinitionsServiceMockModule extends MockitoSugar with ArgumentMatchersSugar with FixedClock {
+
+ protected trait BaseApiFieldDefinitionsServiceMock {
+ def aMock: ApiFieldDefinitionsService
+
+ def verifyZeroInteractions(): Unit = MockitoSugar.verifyZeroInteractions(aMock)
+
+ object Get {
+
+ def returns(context: ApiContext, version: ApiVersionNbr, response: ApiFieldDefinitions) =
+ when(aMock.get(eqTo(context), eqTo(version))).thenReturn(successful(Some(response)))
+
+ def returnsNothing(context: ApiContext, version: ApiVersionNbr) =
+ when(aMock.get(eqTo(context), eqTo(version))).thenReturn(successful(None))
+ }
+ }
+
+ object ApiFieldDefinitionsServiceMock extends BaseApiFieldDefinitionsServiceMock {
+ val aMock = mock[ApiFieldDefinitionsService]
+ }
+}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/mocks/FieldDefinitionRepositoryMockModule.scala b/test/uk/gov/hmrc/apisubscriptionfields/mocks/FieldDefinitionRepositoryMockModule.scala
new file mode 100644
index 0000000..6f3b49e
--- /dev/null
+++ b/test/uk/gov/hmrc/apisubscriptionfields/mocks/FieldDefinitionRepositoryMockModule.scala
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 HM Revenue & Customs
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package uk.gov.hmrc.apisubscriptionfields.mocks
+
+import scala.concurrent.Future.successful
+
+import org.mockito.{ArgumentMatchersSugar, MockitoSugar}
+
+import uk.gov.hmrc.apiplatform.modules.common.domain.models.{ApiContext, ApiVersionNbr}
+import uk.gov.hmrc.apiplatform.modules.common.utils.FixedClock
+
+import uk.gov.hmrc.apisubscriptionfields.model.ApiFieldDefinitions
+import uk.gov.hmrc.apisubscriptionfields.model.Types.IsInsert
+import uk.gov.hmrc.apisubscriptionfields.repository.ApiFieldDefinitionsRepository
+
+trait FieldDefinitionRepositoryMockModule extends MockitoSugar with ArgumentMatchersSugar with FixedClock {
+
+ protected trait BaseFieldDefinitionRepositoryMock {
+ def aMock: ApiFieldDefinitionsRepository
+
+ object Save {
+
+ def returns(definitions: ApiFieldDefinitions, ret: (ApiFieldDefinitions, IsInsert)) =
+ when(aMock.save(eqTo(definitions))).thenReturn(successful(ret))
+ }
+
+ object Fetch {
+
+ def returns(apiContext: ApiContext, apiVersion: ApiVersionNbr, ret: Option[ApiFieldDefinitions]) =
+ when(aMock.fetch(eqTo(apiContext), eqTo(apiVersion))).thenReturn(successful(ret))
+ }
+ }
+
+ object FieldDefinitionRepositoryMock extends BaseFieldDefinitionRepositoryMock {
+ val aMock = mock[ApiFieldDefinitionsRepository]
+ }
+}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/mocks/PushPullNotificationServiceMockModule.scala b/test/uk/gov/hmrc/apisubscriptionfields/mocks/PushPullNotificationServiceMockModule.scala
new file mode 100644
index 0000000..23ffe6d
--- /dev/null
+++ b/test/uk/gov/hmrc/apisubscriptionfields/mocks/PushPullNotificationServiceMockModule.scala
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 HM Revenue & Customs
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package uk.gov.hmrc.apisubscriptionfields.mocks
+
+import scala.concurrent.Future.{failed, successful}
+
+import org.mockito.{ArgumentMatchersSugar, MockitoSugar, Strictness}
+
+import uk.gov.hmrc.apiplatform.modules.common.domain.models.{ApiContext, ApiVersionNbr, ClientId}
+import uk.gov.hmrc.apiplatform.modules.common.utils.FixedClock
+
+import uk.gov.hmrc.apisubscriptionfields.model.BoxId
+import uk.gov.hmrc.apisubscriptionfields.model.Types._
+import uk.gov.hmrc.apisubscriptionfields.service.PushPullNotificationService
+
+trait PushPullNotificationServiceMockModule extends MockitoSugar with ArgumentMatchersSugar with FixedClock {
+
+ protected trait BasePushPullNotificationServiceMock {
+ def aMock: PushPullNotificationService
+
+ def verifyZeroInteractions(): Unit = MockitoSugar.verifyZeroInteractions(aMock)
+
+ object EnsureBoxIsCreated {
+
+ def succeeds(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr, fieldName: FieldName, boxId: BoxId) =
+ when(aMock.ensureBoxIsCreated(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion), eqTo(fieldName))(*)).thenReturn(successful(boxId))
+
+ def fails(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr, fieldName: FieldName) =
+ when(aMock.ensureBoxIsCreated(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion), eqTo(fieldName))(*)).thenReturn(failed(new Exception("bang!")))
+ }
+
+ object UpdateCallbackUrl {
+
+ def succeeds(clientId: ClientId, boxId: BoxId, fieldValue: FieldValue) = {
+ when(aMock.updateCallbackUrl(eqTo(clientId), eqTo(boxId), eqTo(fieldValue))(*)).thenReturn(successful(Right(())))
+ }
+
+ def fails(clientId: ClientId, boxId: BoxId, fieldValue: FieldValue, error: String) =
+ when(aMock.updateCallbackUrl(eqTo(clientId), eqTo(boxId), eqTo(fieldValue))(*)).thenReturn(successful(Left(error)))
+ }
+ }
+
+ object PushPullNotificationServiceMock extends BasePushPullNotificationServiceMock {
+ val aMock = mock[PushPullNotificationService](withSettings.strictness(Strictness.Warn))
+ }
+}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/mocks/SubscriptionFieldsRepositoryMockModule.scala b/test/uk/gov/hmrc/apisubscriptionfields/mocks/SubscriptionFieldsRepositoryMockModule.scala
new file mode 100644
index 0000000..83e4195
--- /dev/null
+++ b/test/uk/gov/hmrc/apisubscriptionfields/mocks/SubscriptionFieldsRepositoryMockModule.scala
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2023 HM Revenue & Customs
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package uk.gov.hmrc.apisubscriptionfields.mocks
+
+import scala.concurrent.Future.{failed, successful}
+
+import org.mockito.{ArgumentMatchersSugar, MockitoSugar}
+
+import uk.gov.hmrc.apiplatform.modules.common.domain.models.{ApiContext, ApiVersionNbr, ClientId}
+import uk.gov.hmrc.apiplatform.modules.common.utils.FixedClock
+
+import uk.gov.hmrc.apisubscriptionfields.model.Types._
+import uk.gov.hmrc.apisubscriptionfields.model.{SubscriptionFields, SubscriptionFieldsId}
+import uk.gov.hmrc.apisubscriptionfields.repository.SubscriptionFieldsRepository
+
+trait SubscriptionFieldsRepositoryMockModule extends MockitoSugar with ArgumentMatchersSugar with FixedClock {
+
+ protected trait BaseSubscriptionFieldsRepositoryMock {
+ def aMock: SubscriptionFieldsRepository
+
+ def verifyZeroInteractions(): Unit = MockitoSugar.verifyZeroInteractions(aMock)
+
+ object FetchAll {
+
+ def returns(list: List[SubscriptionFields]) =
+ when(aMock.fetchAll).thenReturn(successful(list))
+ }
+
+ object FetchByClientId {
+
+ def returns(clientId: ClientId, list: List[SubscriptionFields]) =
+ when(aMock.fetchByClientId(eqTo(clientId))).thenReturn(successful(list))
+ }
+
+ object Fetch {
+
+ def returns(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr, fields: SubscriptionFields) =
+ when(aMock.fetch(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion))).thenReturn(successful(Some(fields)))
+
+ def returnsNone(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr) =
+ when(aMock.fetch(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion))).thenReturn(successful(None))
+ }
+
+ object FetchByFieldsId {
+
+ def returns(id: SubscriptionFieldsId, fields: SubscriptionFields) =
+ when(aMock.fetchByFieldsId(eqTo(id))).thenReturn(successful(Some(fields)))
+
+ def returnsNone(id: SubscriptionFieldsId) =
+ when(aMock.fetchByFieldsId(eqTo(id))).thenReturn(successful(None))
+ }
+
+ object SaveAtomic {
+
+ def returns(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr, fields: SubscriptionFields, isInsert: IsInsert) =
+ when(aMock.saveAtomic(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion), *)).thenReturn(successful((fields, isInsert)))
+
+ def fails(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr, failure: Exception) =
+ when(aMock.saveAtomic(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion), *)).thenReturn(failed(failure))
+
+ def verifyCalled() =
+ verify(aMock, times(1)).saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)
+ }
+
+ object Delete {
+
+ def existsFor(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr) =
+ when(aMock.delete(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion))).thenReturn(successful(true))
+
+ def existsFor(clientId: ClientId) =
+ when(aMock.delete(eqTo(clientId))).thenReturn(successful(true))
+
+ def notExistingFor(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersionNbr) =
+ when(aMock.delete(eqTo(clientId), eqTo(apiContext), eqTo(apiVersion))).thenReturn(successful(false))
+
+ def notExistingFor(clientId: ClientId) =
+ when(aMock.delete(eqTo(clientId))).thenReturn(successful(false))
+ }
+ }
+
+ object SubscriptionFieldsRepositoryMock extends BaseSubscriptionFieldsRepositoryMock {
+ val aMock = mock[SubscriptionFieldsRepository]
+ }
+}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationServiceSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationServiceSpec.scala
index d60bc2c..509bd2d 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationServiceSpec.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/service/PushPullNotificationServiceSpec.scala
@@ -17,14 +17,12 @@
package uk.gov.hmrc.apisubscriptionfields.service
import java.{util => ju}
-import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future.{failed, successful}
import uk.gov.hmrc.apiplatform.modules.common.domain.models._
import uk.gov.hmrc.http.HeaderCarrier
import uk.gov.hmrc.apisubscriptionfields.connector.PushPullNotificationServiceConnector
-import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinitionType._
import uk.gov.hmrc.apisubscriptionfields.model._
import uk.gov.hmrc.apisubscriptionfields.{AsyncHmrcSpec, FieldDefinitionTestData, SubscriptionFieldsTestData}
@@ -43,60 +41,52 @@ class PushPullNotificationServiceSpec extends AsyncHmrcSpec with SubscriptionFie
val service = new PushPullNotificationService(mockPPNSConnector)
}
- "subscribing to PPNS" should {
- val ppnsFieldName = fieldN(1)
- val callbackUrl = "123"
- val oCallbackUrl = Some(callbackUrl)
- val ppnsFieldDefinition = FieldDefinition(ppnsFieldName, "description-1", "hint-1", PPNS_FIELD, "short-description-1")
- val expectedTopicName = s"${apiContext.value}##${apiVersionNbr.value}##$ppnsFieldName"
+ "creating PPNS box when needed" should {
+ val ppnsFieldName = fieldN(1)
+ val expectedTopicName = s"${apiContext.value}##${apiVersionNbr.value}##$ppnsFieldName"
- "succeed and return PPNSCallBackUrlSuccessResponse when update of callback URL is successful" in new Setup {
+ "succeed when box is created" in new Setup {
when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(successful(boxId))
- when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, callbackUrl)(hc)).thenReturn(successful(PPNSCallBackUrlSuccessResponse))
- val result: PPNSCallBackUrlValidationResponse = await(service.subscribeToPPNS(clientId, apiContext, apiVersionNbr, oCallbackUrl, ppnsFieldDefinition))
+ val result = await(service.ensureBoxIsCreated(clientId, apiContext, apiVersionNbr, ppnsFieldName))
- result shouldBe PPNSCallBackUrlSuccessResponse
- verify(mockPPNSConnector).ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)
- verify(mockPPNSConnector).updateCallBackUrl(eqTo(clientId), eqTo(boxId), eqTo(callbackUrl))(*)
+ result shouldBe boxId
}
- "succeed and return PPNSCallBackUrlSuccessResponse but not call updatecallBackUrl when field is empty" in new Setup {
- when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(successful(boxId))
-
- val result: PPNSCallBackUrlValidationResponse = await(service.subscribeToPPNS(clientId, apiContext, apiVersionNbr, None, ppnsFieldDefinition))
+ "fail when box creation fails" in new Setup {
+ when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(failed(new RuntimeException))
- result shouldBe PPNSCallBackUrlSuccessResponse
- verify(mockPPNSConnector).ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)
- verify(mockPPNSConnector, times(0)).updateCallBackUrl(eqTo(clientId), eqTo(boxId), eqTo(callbackUrl))(*)
+ intercept[RuntimeException] {
+ await(service.ensureBoxIsCreated(clientId, apiContext, apiVersionNbr, ppnsFieldName))
+ }
}
+ }
- "return PPNSCallBackUrlFailedResponse when update of callback URL fails" in new Setup {
- val errorMessage = "Error Message"
- when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(successful(boxId))
- when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, callbackUrl)(hc)).thenReturn(successful(PPNSCallBackUrlFailedResponse(errorMessage)))
+ "updating PPNS callback URL" should {
+ val ppnsFieldValue = "localhost:9001/pingme"
- val result: PPNSCallBackUrlValidationResponse = await(service.subscribeToPPNS(clientId, apiContext, apiVersionNbr, oCallbackUrl, ppnsFieldDefinition))
+ "succeed when update of callback URL is successful" in new Setup {
+ when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, ppnsFieldValue)(hc)).thenReturn(successful(Right(())))
- result shouldBe PPNSCallBackUrlFailedResponse(errorMessage)
- verify(mockPPNSConnector).ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)
- verify(mockPPNSConnector).updateCallBackUrl(eqTo(clientId), eqTo(boxId), eqTo(callbackUrl))(*)
+ val result = await(service.updateCallbackUrl(clientId, boxId, ppnsFieldValue))
+
+ result shouldBe Right(())
}
- "fail when box creation fails" in new Setup {
- when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(failed(new RuntimeException))
+ "fail when update of callback URL fails with an error message" in new Setup {
+ val errorMessage = "Error Message"
+ when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, ppnsFieldValue)(hc)).thenReturn(successful(Left(errorMessage)))
- intercept[RuntimeException] {
- await(service.subscribeToPPNS(clientId, apiContext, apiVersionNbr, oCallbackUrl, ppnsFieldDefinition))
- }
+ val result = await(service.updateCallbackUrl(clientId, boxId, ppnsFieldValue))
+
+ result shouldBe Left(errorMessage)
}
- "fail when update callback url fails" in new Setup {
- when(mockPPNSConnector.ensureBoxIsCreated(eqTo(expectedTopicName), eqTo(clientId))(*)).thenReturn(successful(boxId))
- when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, callbackUrl)(hc)).thenReturn(failed(new RuntimeException))
+ "fail when update of callback URL fails with an exception" in new Setup {
+ when(mockPPNSConnector.updateCallBackUrl(clientId, boxId, ppnsFieldValue)(hc)).thenReturn(failed(new RuntimeException))
intercept[RuntimeException] {
- await(service.subscribeToPPNS(clientId, apiContext, apiVersionNbr, oCallbackUrl, ppnsFieldDefinition))
+ await(service.updateCallbackUrl(clientId, boxId, ppnsFieldValue))
}
}
}
diff --git a/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala
index 3c5f074..7258752 100644
--- a/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala
+++ b/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala
@@ -17,35 +17,62 @@
package uk.gov.hmrc.apisubscriptionfields.service
import scala.concurrent.ExecutionContext.Implicits.global
-import scala.concurrent.Future.{failed, successful}
import cats.data.NonEmptyList
+import org.mockito.scalatest.IdiomaticMockito
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
-import uk.gov.hmrc.apiplatform.modules.common.domain.models._
+import play.api.test.{DefaultAwaitTimeout, FutureAwaits}
import uk.gov.hmrc.http.HeaderCarrier
-import uk.gov.hmrc.apisubscriptionfields.model.Types.FieldErrorMap
+import uk.gov.hmrc.apisubscriptionfields.mocks.{SubscriptionFieldsRepositoryMockModule, _}
+import uk.gov.hmrc.apisubscriptionfields.model.Types._
import uk.gov.hmrc.apisubscriptionfields.model._
-import uk.gov.hmrc.apisubscriptionfields.repository._
-import uk.gov.hmrc.apisubscriptionfields.{AsyncHmrcSpec, FieldDefinitionTestData, SubscriptionFieldsTestData}
+import uk.gov.hmrc.apisubscriptionfields.{FieldDefinitionTestData, SubscriptionFieldsTestData}
-class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionFieldsTestData with FieldDefinitionTestData {
-
- trait Setup {
- val mockSubscriptionFieldsRepository: SubscriptionFieldsMongoRepository = mock[SubscriptionFieldsMongoRepository]
- val mockApiFieldDefinitionsService: ApiFieldDefinitionsService = mock[ApiFieldDefinitionsService]
- val mockPushPullNotificationService: PushPullNotificationService = mock[PushPullNotificationService](org.mockito.Mockito.withSettings().verboseLogging())
+class SubscriptionFieldsServiceSpec extends AnyWordSpec with DefaultAwaitTimeout with FutureAwaits with Matchers with SubscriptionFieldsTestData with FieldDefinitionTestData
+ with IdiomaticMockito {
+ trait Setup extends ApiFieldDefinitionsServiceMockModule with SubscriptionFieldsRepositoryMockModule with PushPullNotificationServiceMockModule {
implicit val hc: HeaderCarrier = HeaderCarrier()
val service =
- new SubscriptionFieldsService(mockSubscriptionFieldsRepository, mockApiFieldDefinitionsService, mockPushPullNotificationService)
+ new SubscriptionFieldsService(SubscriptionFieldsRepositoryMock.aMock, ApiFieldDefinitionsServiceMock.aMock, PushPullNotificationServiceMock.aMock)
+
+ val validSubsFields: SubscriptionFields = subsFieldsFor(SubscriptionFieldsMatchRegexValidation)
+ val otherValidSubsFields = subsFieldsFor(SubscriptionFieldsMatchRegexValidation + (AlphanumericFieldName -> "CBA321"))
+ def validSubsFieldsWithPpnsValue(fieldValue: FieldValue) = subsFieldsFor(SubscriptionFieldsMatchRegexValidation + (PPNSFieldFieldName -> fieldValue))
+ val validPpnsSubsFields: SubscriptionFields = validSubsFieldsWithPpnsValue(PPNSFieldFieldValue)
+
+ val subsFieldsFailingValidation: SubscriptionFields = subsFieldsFor(Map(AlphanumericFieldName -> "ABC 123", PasswordFieldName -> "Qw12@er"))
+ val noSubsFields = validSubsFields.copy(fields = Map.empty)
+
+ def thereAreNoFieldDefinitions() = ApiFieldDefinitionsServiceMock.Get.returnsNothing(FakeContext, FakeVersion)
+ def thereAreFieldDefinitions() = ApiFieldDefinitionsServiceMock.Get.returns(FakeContext, FakeVersion, FakeApiFieldDefinitionsResponseWithRegex)
+ def thereArePpnsFieldDefinitions() = ApiFieldDefinitionsServiceMock.Get.returns(FakeContext, FakeVersion, FakeApiFieldDefinitionsResponsePPNSWithRegex)
+
+ def thereAreNoExistingFieldValues() = SubscriptionFieldsRepositoryMock.Fetch.returnsNone(FakeClientId, FakeContext, FakeVersion)
+ def thereAreExistingFieldValues(fields: SubscriptionFields) = SubscriptionFieldsRepositoryMock.Fetch.returns(FakeClientId, FakeContext, FakeVersion, fields)
+ def thereAreExistingFieldsWithoutValues() = thereAreExistingFieldValues(noSubsFields)
+ def thereAreExistingPpnsFieldValues() = thereAreExistingFieldValues(validPpnsSubsFields)
+
+ def callToEnsurePpnsBoxIsPresent() = PushPullNotificationServiceMock.EnsureBoxIsCreated.succeeds(FakeClientId, FakeContext, FakeVersion, PPNSFieldFieldName, FakeBoxId)
+ def callToEnsurePpnsBoxIsPresentFails() = PushPullNotificationServiceMock.EnsureBoxIsCreated.fails(FakeClientId, FakeContext, FakeVersion, PPNSFieldFieldName)
+
+ def ppnsFieldGetsUpdated(fieldValue: FieldValue = PPNSFieldFieldValue) =
+ PushPullNotificationServiceMock.UpdateCallbackUrl.succeeds(FakeClientId, FakeBoxId, fieldValue)
+ def ppnsFieldUpdateFails(error: String) =
+ PushPullNotificationServiceMock.UpdateCallbackUrl.fails(FakeClientId, FakeBoxId, PPNSFieldFieldValue, error)
+
+ def fieldsAreCreatedInDB(whichFields: SubscriptionFields) = SubscriptionFieldsRepositoryMock.SaveAtomic.returns(FakeClientId, FakeContext, FakeVersion, whichFields, true)
+ def fieldsAreUpdatedInDB(whichFields: SubscriptionFields) = SubscriptionFieldsRepositoryMock.SaveAtomic.returns(FakeClientId, FakeContext, FakeVersion, whichFields, false)
}
"getAll" should {
"return an empty list when no entry exists in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.fetchAll).thenReturn(successful(List.empty))
+ SubscriptionFieldsRepositoryMock.FetchAll.returns(List.empty)
await(service.getAll) shouldBe BulkSubscriptionFieldsResponse(subscriptions = List())
}
@@ -54,7 +81,7 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
val sf1: SubscriptionFields = createSubscriptionFieldsWithApiContext(FakeClientId)
val sf2: SubscriptionFields = createSubscriptionFieldsWithApiContext(FakeClientId2)
- when(mockSubscriptionFieldsRepository.fetchAll).thenReturn(successful(List(sf1, sf2)))
+ SubscriptionFieldsRepositoryMock.FetchAll.returns(List(sf1, sf2))
val expectedResponse: BulkSubscriptionFieldsResponse = BulkSubscriptionFieldsResponse(subscriptions =
List(
@@ -69,7 +96,7 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
"get by clientId" should {
"return None when the expected record does not exist in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.fetchByClientId(FakeClientId)).thenReturn(successful(List()))
+ SubscriptionFieldsRepositoryMock.FetchByClientId.returns(FakeClientId, List())
await(service.getByClientId(FakeClientId)) shouldBe None
}
@@ -77,7 +104,7 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
"return the expected response when the entry exists in the database collection" in new Setup {
val sf1: SubscriptionFields = createSubscriptionFieldsWithApiContext()
val sf2: SubscriptionFields = createSubscriptionFieldsWithApiContext(rawContext = fakeRawContext2)
- when(mockSubscriptionFieldsRepository.fetchByClientId(FakeClientId)).thenReturn(successful(List(sf1, sf2)))
+ SubscriptionFieldsRepositoryMock.FetchByClientId.returns(FakeClientId, List(sf1, sf2))
val result: Option[BulkSubscriptionFieldsResponse] = await(service.getByClientId(FakeClientId))
@@ -94,13 +121,12 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
"get" should {
"return None when no entry exists in the repo" in new Setup {
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(None))
-
+ thereAreNoExistingFieldValues()
await(service.get(FakeClientId, FakeContext, FakeVersion)) shouldBe None
}
"return the expected response when the entry exists in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiSubscription)))
+ SubscriptionFieldsRepositoryMock.Fetch.returns(FakeClientId, FakeContext, FakeVersion, FakeApiSubscription)
val result: Option[SubscriptionFields] = await(service.get(FakeClientId, FakeContext, FakeVersion))
@@ -110,143 +136,165 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
"get by fieldsId" should {
"return None when no entry exists in the repo" in new Setup {
- when(mockSubscriptionFieldsRepository.fetchByFieldsId(SubscriptionFieldsId(FakeRawFieldsId))).thenReturn(successful(None))
+ SubscriptionFieldsRepositoryMock.FetchByFieldsId.returnsNone(SubscriptionFieldsId(FakeRawFieldsId))
await(service.getBySubscriptionFieldId(FakeFieldsId)) shouldBe None
}
"return the expected response when the entry exists in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.fetchByFieldsId(SubscriptionFieldsId(FakeRawFieldsId))).thenReturn(successful(Some(FakeApiSubscription)))
+ SubscriptionFieldsRepositoryMock.FetchByFieldsId.returns(SubscriptionFieldsId(FakeRawFieldsId), FakeApiSubscription)
await(service.getBySubscriptionFieldId(FakeFieldsId)) shouldBe Some(FakeSubscriptionFieldsResponse)
}
}
"upsert" should {
- val fieldsNonMatch: Types.Fields = SubscriptionFieldsNonMatchRegexValidation
- val fields: Types.Fields = SubscriptionFieldsMatchRegexValidation
- val subscriptionFieldsNonMatch: SubscriptionFields = subsFieldsFor(fieldsNonMatch)
- val subscriptionFieldsMatching: SubscriptionFields = subsFieldsFor(fields)
- val ppnsSuccessResponse = successful(PPNSCallBackUrlSuccessResponse)
- val ppnsFailureResponse = successful(PPNSCallBackUrlFailedResponse("An Error Occurred"))
-
- "return false when updating an existing api subscription fields (no PPNS)" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponseWithRegex)))
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsNonMatch, false)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsMatching))))
+ "succeed in creating a new api subscription fields" in new Setup {
+ thereAreFieldDefinitions()
+ thereAreExistingFieldsWithoutValues()
+ fieldsAreCreatedInDB(validSubsFields)
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation))
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validSubsFields.fields))
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fields), isInsert = false)
- verifyZeroInteractions(mockPushPullNotificationService)
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validSubsFields.fields), isInsert = true)
}
- "return false when updating an existing api subscription fields where all fields match (no PPNS)" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponseWithRegex)))
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsMatching, false)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsMatching))))
+ "succeed without updating because all fields match (no PPNSField definition)" in new Setup {
+ thereAreFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation))
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validSubsFields.fields))
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fields), isInsert = false)
- verifyZeroInteractions(mockPushPullNotificationService)
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validSubsFields.fields), isInsert = false)
}
- "return false when updating an existing api subscription fields (has PPNS)" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponsePPNSWithRegex)))
- when(mockPushPullNotificationService.subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any))
- .thenReturn(ppnsSuccessResponse)
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsNonMatch, false)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "not fail when identical subs fields presented but no definitions exist (anymore)" in new Setup {
+ thereAreNoFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidationPPNS))
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validSubsFields.fields))
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fieldsNonMatch), isInsert = false)
-
- verify(mockPushPullNotificationService).subscribeToPPNS(
- eqTo(FakeClientId),
- eqTo(FakeContext),
- eqTo(FakeVersion),
- eqTo(Some("https://www.mycallbackurl.com")),
- any[FieldDefinition]
- )(any)
- verify(mockSubscriptionFieldsRepository).saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validSubsFields.fields), isInsert = false)
}
- "return false when updating an existing api subscription field with empty string callback URL for PPNS" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponsePPNSWithRegex)))
- when(mockPushPullNotificationService.subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any))
- .thenReturn(ppnsSuccessResponse)
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsNonMatch, false)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "not fail when changed subs fields presented but no definitions exist (anymore)" in new Setup {
+ thereAreNoFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, otherValidSubsFields.fields))
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsEmptyValueRegexValidationPPNS))
+ result shouldBe NotFoundSubsFieldsUpsertResponse
+ }
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fieldsNonMatch), isInsert = false)
+ "succeed updating an existing api subscription field because fields don't all match (no PPNSField definition)" in new Setup {
+ thereAreFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+ fieldsAreUpdatedInDB(otherValidSubsFields)
- verify(mockPushPullNotificationService).subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), eqTo(Some("")), any[FieldDefinition])(any)
- verify(mockSubscriptionFieldsRepository).saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, otherValidSubsFields.fields))
+
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, otherValidSubsFields.fields), isInsert = false)
}
- "return PPNSCallBackUrlSuccessResponse when updating an existing api subscription field for PPNS is not included" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponsePPNSWithRegex)))
- when(mockPushPullNotificationService.subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any))
- .thenReturn(ppnsSuccessResponse)
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsNonMatch, false)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "fail validation when upserting with an invalid field value (no PPNSField definition)" in new Setup {
+ thereAreFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, subsFieldsFailingValidation.fields))
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation))
+ result shouldBe FailedValidationSubsFieldsUpsertResponse(Map(
+ AlphanumericFieldName -> FakeFieldDefinitionAlphnumericField.validation.get.errorMessage,
+ PasswordFieldName -> FakeFieldDefinitionPassword.validation.get.errorMessage
+ ))
+ }
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fieldsNonMatch), isInsert = false)
+ "succeed creating a new api subscription fields with PPNS field value" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreExistingFieldsWithoutValues()
+ callToEnsurePpnsBoxIsPresent()
+ ppnsFieldGetsUpdated()
+ fieldsAreCreatedInDB(validPpnsSubsFields)
- verify(mockPushPullNotificationService).subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any)
- verify(mockSubscriptionFieldsRepository).saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validPpnsSubsFields.fields))
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validPpnsSubsFields.fields), isInsert = true)
}
- "return FailedValidationSubsFieldsUpsertResponse when updating an existing api subscription fields and PPNS service returns failure" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponsePPNSWithRegex)))
- when(mockPushPullNotificationService.subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any))
- .thenReturn(ppnsFailureResponse)
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "succeed without updating PPNS field because all fields match but ensure PPNS box creation occurs - APSR-1788" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreExistingPpnsFieldValues()
+ callToEnsurePpnsBoxIsPresent()
+
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validPpnsSubsFields.fields))
+
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validPpnsSubsFields.fields), isInsert = false)
+ }
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidationPPNS))
+ "succeed when PPNS field definition is added to an API with an already subscribed app, update PPNS field to empty string and ensure PPNS box creation occurs - APSR-1788" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+ callToEnsurePpnsBoxIsPresent()
+ ppnsFieldGetsUpdated("")
+ val fieldsWithPpnsEmptyValue = validSubsFieldsWithPpnsValue("")
+ fieldsAreUpdatedInDB(fieldsWithPpnsEmptyValue)
- result shouldBe FailedValidationSubsFieldsUpsertResponse(Map(PPNSFieldFieldName -> "An Error Occurred"))
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, fieldsWithPpnsEmptyValue.fields))
- verify(mockPushPullNotificationService).subscribeToPPNS(eqTo(FakeClientId), eqTo(FakeContext), eqTo(FakeVersion), any, any[FieldDefinition])(any)
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fieldsWithPpnsEmptyValue.fields), isInsert = false)
}
- "return FailedValidationSubsFieldsUpsertResponse when updating an existing api subscription fields and PPNS field fails validation" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponsePPNSWithRegex)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "handle having no PPNS field value in the new fields but saves other fields due to changed values" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+ fieldsAreUpdatedInDB(otherValidSubsFields)
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsDoNotMatchRegexValidationPPNS))
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, otherValidSubsFields.fields))
- result shouldBe FailedValidationSubsFieldsUpsertResponse(Map(PPNSFieldFieldName -> "CallBackUrl Validation"))
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, otherValidSubsFields.fields), isInsert = false)
+ }
+
+ "handle PPNS subscription returning validation errors" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreNoExistingFieldValues()
+ callToEnsurePpnsBoxIsPresent()
+ ppnsFieldUpdateFails("Bobbins")
+
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validPpnsSubsFields.fields))
- verifyZeroInteractions(mockPushPullNotificationService)
+ result shouldBe FailedValidationSubsFieldsUpsertResponse(Map(PPNSFieldFieldName -> "Bobbins"))
}
- "return true when creating a new api subscription fields" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponseWithRegex)))
+ "succeed updating an existing api subscription field because fields dont all match and PPNS subscribe is required" in new Setup {
+ thereArePpnsFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+ callToEnsurePpnsBoxIsPresent()
+ ppnsFieldGetsUpdated()
+ fieldsAreUpdatedInDB(validPpnsSubsFields)
+
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, validPpnsSubsFields.fields))
+
+ result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, validPpnsSubsFields.fields), isInsert = false)
+ }
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(successful((subscriptionFieldsNonMatch, true)))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ "fail validation when upserting with a bad PPNS field value and don't subscribe PPNS" in new Setup {
+ thereArePpnsFieldDefinitions()
+ SubscriptionFieldsRepositoryMock.Fetch.returns(FakeClientId, FakeContext, FakeVersion, subsFieldsFailingValidation)
- val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation))
+ final val BadPpnsValue = "xxx"
+ val baseFields = SubscriptionFieldsMatchRegexValidationPPNS
+ val fieldsWithInvalidPpnsValue = baseFields + (PPNSFieldFieldName -> BadPpnsValue)
+ val result: SubsFieldsUpsertResponse = await(service.upsert(FakeClientId, FakeContext, FakeVersion, fieldsWithInvalidPpnsValue))
- result shouldBe SuccessfulSubsFieldsUpsertResponse(SubscriptionFields(FakeClientId, FakeContext, FakeVersion, FakeFieldsId, fieldsNonMatch), isInsert = true)
- verifyZeroInteractions(mockPushPullNotificationService)
+ result shouldBe FailedValidationSubsFieldsUpsertResponse(Map(PPNSFieldFieldName -> FakeFieldDefinitionPPNSFields.validation.get.errorMessage))
}
"propagate the error" in new Setup {
- when(mockApiFieldDefinitionsService.get(FakeContext, FakeVersion)).thenReturn(successful(Some(FakeApiFieldDefinitionsResponseWithRegex)))
- when(mockSubscriptionFieldsRepository.saveAtomic(*[ClientId], *[ApiContext], *[ApiVersionNbr], *)).thenReturn(failed(emulatedFailure))
- when(mockSubscriptionFieldsRepository.fetch(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(Some((subscriptionFieldsNonMatch))))
+ thereAreFieldDefinitions()
+ thereAreExistingFieldValues(validSubsFields)
+ SubscriptionFieldsRepositoryMock.SaveAtomic.fails(FakeClientId, FakeContext, FakeVersion, emulatedFailure)
val caught: EmulatedFailure = intercept[EmulatedFailure] {
- await(service.upsert(FakeClientId, FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation))
+ await(service.upsert(FakeClientId, FakeContext, FakeVersion, otherValidSubsFields.fields))
}
caught shouldBe emulatedFailure
@@ -255,25 +303,25 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
"delete" should {
"return true when the entry exists in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.delete(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(true))
+ SubscriptionFieldsRepositoryMock.Delete.existsFor(FakeClientId, FakeContext, FakeVersion)
await(service.delete(FakeClientId, FakeContext, FakeVersion)) shouldBe true
}
"return false when the entry does not exist in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.delete(FakeClientId, FakeContext, FakeVersion)).thenReturn(successful(false))
+ SubscriptionFieldsRepositoryMock.Delete.notExistingFor(FakeClientId, FakeContext, FakeVersion)
await(service.delete(FakeClientId, FakeContext, FakeVersion)) shouldBe false
}
"return true when the client ID exists in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.delete(FakeClientId)).thenReturn(successful(true))
+ SubscriptionFieldsRepositoryMock.Delete.existsFor(FakeClientId)
await(service.delete(FakeClientId)) shouldBe true
}
"return false when the client ID does not exist in the database collection" in new Setup {
- when(mockSubscriptionFieldsRepository.delete(FakeClientId)).thenReturn(successful(false))
+ SubscriptionFieldsRepositoryMock.Delete.notExistingFor(FakeClientId)
await(service.delete(FakeClientId)) shouldBe false
}
@@ -295,7 +343,7 @@ class SubscriptionFieldsServiceSpec extends AsyncHmrcSpec with SubscriptionField
}
}
- "validate value against field defintion" should {
+ "validate value against field definition" should {
val fieldDefintionWithoutValidation = FieldDefinition(fieldN(1), "desc1", "hint1", FieldDefinitionType.URL, "short description", None)
val fieldDefinitionWithValidation = fieldDefintionWithoutValidation.copy(validation = Some(validationGroup1))