diff --git a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/AcceptanceTestSpec.scala b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/AcceptanceTestSpec.scala index 9fc87c7..b3aae04 100644 --- a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/AcceptanceTestSpec.scala +++ b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/AcceptanceTestSpec.scala @@ -37,14 +37,14 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scala.concurrent.{Await, Future} import cats.data.NonEmptyList -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData trait AcceptanceTestSpec extends FeatureSpec with GivenWhenThen with BeforeAndAfterAll with Matchers with GuiceOneServerPerSuite - with FieldsDefinitionTestData { + with FieldDefinitionTestData { protected val ValidRequest = FakeRequest() .withHeaders(RequestHeaders.ACCEPT_HMRC_JSON_HEADER) @@ -74,9 +74,9 @@ trait AcceptanceTestSpec extends FeatureSpec fakeRequestWithHeaders.withMethod(PUT).withJsonBody(Json.toJson(contents)) protected def validDefinitionPutRequest(fieldDefinitions: NonEmptyList[FieldDefinition]): FakeRequest[AnyContentAsJson] = - validDefinitionPutRequest(FieldsDefinitionRequest(fieldDefinitions)) + validDefinitionPutRequest(FieldDefinitionsRequest(fieldDefinitions)) - protected def validDefinitionPutRequest(contents: FieldsDefinitionRequest): FakeRequest[AnyContentAsJson] = + protected def validDefinitionPutRequest(contents: FieldDefinitionsRequest): FakeRequest[AnyContentAsJson] = fakeRequestWithHeaders.withMethod(PUT).withJsonBody(Json.toJson(contents)) protected def fakeRequestWithHeaders: FakeRequest[AnyContentAsEmpty.type] = { diff --git a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/ApiSubscriptionFieldsHappySpec.scala b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/ApiSubscriptionFieldsHappySpec.scala index 87f0e90..42f9d49 100644 --- a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/ApiSubscriptionFieldsHappySpec.scala +++ b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/ApiSubscriptionFieldsHappySpec.scala @@ -25,20 +25,20 @@ import play.api.mvc.request.RequestTarget import play.api.test.FakeRequest import play.api.test.Helpers._ import uk.gov.hmrc.apisubscriptionfields.model._ -import uk.gov.hmrc.apisubscriptionfields.{FieldsDefinitionTestData, SubscriptionFieldsTestData} +import uk.gov.hmrc.apisubscriptionfields.{FieldDefinitionTestData, SubscriptionFieldsTestData} import scala.concurrent.Future - import scala.concurrent.Await - import scala.concurrent.duration._ +import scala.concurrent.Await +import scala.concurrent.duration._ class ApiSubscriptionFieldsHappySpec extends AcceptanceTestSpec with OptionValues with JsonFormatters with SubscriptionFieldsTestData - with FieldsDefinitionTestData + with FieldDefinitionTestData with BeforeAndAfterAll { override def beforeAll() { - val putRequest = validDefinitionPutRequest(FieldsDefinitionRequest(FakeFieldsDefinitions)) + val putRequest = validDefinitionPutRequest(FieldDefinitionsRequest(NelOfFieldDefinitions)) .withTarget( RequestTarget(uriString="", path=definitionEndpoint(fakeRawContext, fakeRawVersion), queryString = Map.empty)) Await.result(route(app, putRequest).get, 10.seconds) diff --git a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/SubscriptionFieldDefinitionsHappySpec.scala b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/SubscriptionFieldDefinitionsHappySpec.scala index 4e26174..d0d58b3 100644 --- a/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/SubscriptionFieldDefinitionsHappySpec.scala +++ b/acceptance/uk/gov/hmrc/apisubscriptionfields/acceptance/SubscriptionFieldDefinitionsHappySpec.scala @@ -21,23 +21,23 @@ import play.api.mvc._ import play.api.mvc.request.RequestTarget import play.api.test.Helpers._ import uk.gov.hmrc.apisubscriptionfields.model._ -import uk.gov.hmrc.apisubscriptionfields.{FieldsDefinitionTestData, SubscriptionFieldsTestData} +import uk.gov.hmrc.apisubscriptionfields.{FieldDefinitionTestData, SubscriptionFieldsTestData} import scala.concurrent.Future class SubscriptionFieldDefinitionsHappySpec extends AcceptanceTestSpec with OptionValues with SubscriptionFieldsTestData - with FieldsDefinitionTestData + with FieldDefinitionTestData with JsonFormatters { - - + + feature("Fields-Definition") { scenario("the API is called to store some new fields definitions") { Given("Definitiions are created ") - val putRequest = validDefinitionPutRequest(FieldsDefinitionRequest(FakeFieldsDefinitions)) + val putRequest = validDefinitionPutRequest(FieldDefinitionsRequest(NelOfFieldDefinitions)) .withTarget( RequestTarget(uriString="", path=definitionEndpoint(fakeRawContext, fakeRawVersion), queryString = Map.empty)) When("a PUT request with data is sent to the API") @@ -50,10 +50,10 @@ class SubscriptionFieldDefinitionsHappySpec extends AcceptanceTestSpec status(putResultFuture) shouldBe CREATED And("the response body should be a valid response") - val sfr = contentAsJson(putResultFuture).validate[FieldsDefinitionResponse] + val sfr = contentAsJson(putResultFuture).validate[ApiFieldDefinitionsResponse] sfr.isSuccess shouldBe true - sfr.get shouldBe FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions) + sfr.get shouldBe ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions) } @@ -76,10 +76,10 @@ class SubscriptionFieldDefinitionsHappySpec extends AcceptanceTestSpec status(resultFuture) shouldBe OK And("the response body should be a valid response") - val fdr = contentAsJson(resultFuture).validate[FieldsDefinitionResponse] + val fdr = contentAsJson(resultFuture).validate[ApiFieldDefinitionsResponse] fdr.isSuccess shouldBe true - fdr.get shouldBe FakeFieldsDefinitionResponse + fdr.get shouldBe FakeApiFieldDefinitionsResponse } scenario("the API is called to GET all fields definitions") { @@ -99,16 +99,16 @@ class SubscriptionFieldDefinitionsHappySpec extends AcceptanceTestSpec status(resultFuture) shouldBe OK And("the response body should be a valid response") - val allFdr = contentAsJson(resultFuture).validate[BulkFieldsDefinitionsResponse] + val allFdr = contentAsJson(resultFuture).validate[BulkApiFieldDefinitionsResponse] allFdr.isSuccess shouldBe true - allFdr.get shouldBe BulkFieldsDefinitionsResponse(List(FakeFieldsDefinitionResponse)) + allFdr.get shouldBe BulkApiFieldDefinitionsResponse(List(FakeApiFieldDefinitionsResponse)) } scenario("the API is called to update some existing fields definitions") { Given("a request with valid payload") - val request = validDefinitionPutRequest(FieldsDefinitionRequest(FakeFieldsDefinitions)) + val request = validDefinitionPutRequest(FieldDefinitionsRequest(NelOfFieldDefinitions)) .withTarget( RequestTarget(uriString="", path=definitionEndpoint(fakeRawContext, fakeRawVersion), queryString = Map.empty)) When("a PUT request with data is sent to the API") @@ -117,14 +117,13 @@ class SubscriptionFieldDefinitionsHappySpec extends AcceptanceTestSpec Then(s"a response with a 200 status is received") result shouldBe 'defined val resultFuture = result.value - status(resultFuture) shouldBe OK And("the response body should be a valid response") - val sfr = contentAsJson(resultFuture).validate[FieldsDefinitionResponse] + val sfr = contentAsJson(resultFuture).validate[ApiFieldDefinitionsResponse] sfr.isSuccess shouldBe true - sfr.get shouldBe FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions) + sfr.get shouldBe ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions) } scenario("the API is called to delete some existing fields definitions") { diff --git a/app/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionController.scala b/app/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsController.scala similarity index 87% rename from app/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionController.scala rename to app/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsController.scala index dc6fd9e..3b35ba6 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionController.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsController.scala @@ -21,16 +21,16 @@ import javax.inject.{Inject, Singleton} import play.api.libs.json.{JsValue, Json, JsSuccess, JsError} import play.api.mvc._ import uk.gov.hmrc.apisubscriptionfields.model._ -import uk.gov.hmrc.apisubscriptionfields.service.FieldsDefinitionService -import scala.concurrent.ExecutionContext.Implicits.global +import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService import scala.concurrent.Future import scala.util.{Try,Success,Failure} import play.api.Logger import java.util.UUID +import scala.concurrent.ExecutionContext @Singleton -class FieldsDefinitionController @Inject() (cc: ControllerComponents, service: FieldsDefinitionService) extends CommonController { +class ApiFieldDefinitionsController @Inject() (cc: ControllerComponents, service: ApiFieldDefinitionsService)(implicit ec: ExecutionContext) extends CommonController { import JsonFormatters._ @@ -44,7 +44,7 @@ class FieldsDefinitionController @Inject() (cc: ControllerComponents, service: F NotFound(JsErrorResponse(ErrorCode.NOT_FOUND_CODE, s"Fields definition not found for (${apiContext.value}, ${apiVersion.value})")) def validateFieldsDefinition(): Action[JsValue] = Action(parse.json) { request => - Try(request.body.validate[FieldsDefinitionRequest]) match { + Try(request.body.validate[FieldDefinitionsRequest]) match { case Success(JsSuccess(payload, _)) => Ok("") case Success(JsError(errs)) => { badRequestWithTag( (tag:UUID) => s"A JSON error occurred: [${tag.toString}] ${Json.prettyPrint(JsError.toJson(errs))}") @@ -56,7 +56,7 @@ class FieldsDefinitionController @Inject() (cc: ControllerComponents, service: F } def upsertFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion): Action[JsValue] = Action.async(parse.json) { implicit request => - withJsonBody[FieldsDefinitionRequest] { payload => + withJsonBody[FieldDefinitionsRequest] { payload => service.upsert(apiContext, apiVersion, payload.fieldDefinitions) map { case (response, true) => Created(Json.toJson(response)) case (response, false) => Ok(Json.toJson(response)) @@ -80,7 +80,7 @@ class FieldsDefinitionController @Inject() (cc: ControllerComponents, service: F } recover recovery } - private def asActionResult(eventualMaybeResponse: Future[Option[FieldsDefinitionResponse]], apiContext: ApiContext, apiVersion: ApiVersion) = { + private def asActionResult(eventualMaybeResponse: Future[Option[ApiFieldDefinitionsResponse]], apiContext: ApiContext, apiVersion: ApiVersion) = { eventualMaybeResponse map { case Some(subscriptionFields) => Ok(Json.toJson(subscriptionFields)) case None => notFoundResponse(apiContext, apiVersion) diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirements.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirements.scala new file mode 100644 index 0000000..cc4a40d --- /dev/null +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirements.scala @@ -0,0 +1,70 @@ +/* + * Copyright 2020 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.model + +sealed trait DevhubAccessRequirement +object DevhubAccessRequirement { + final val Default: DevhubAccessRequirement = Anyone + + case object NoOne extends DevhubAccessRequirement + case object AdminOnly extends DevhubAccessRequirement + case object Anyone extends DevhubAccessRequirement +} + +case class DevhubAccessRequirements private ( + val read: DevhubAccessRequirement, + val write: DevhubAccessRequirement) { + def satisfiesRead(dal: DevhubAccessLevel): Boolean = dal.satisfiesRequirement(read) // ReadWrite will be at least as strict. + def satisfiesWrite(dal: DevhubAccessLevel): Boolean = dal.satisfiesRequirement(write) +} + + +object DevhubAccessRequirements { + import DevhubAccessRequirement._ + + final val Default = new DevhubAccessRequirements(DevhubAccessRequirement.Default, DevhubAccessRequirement.Default) + + // Do not allow greater restrictions on read than on write + // - it would make no sense to allow NoOne read but everyone write or developer write and admin read + // + def apply(read: DevhubAccessRequirement, write: DevhubAccessRequirement = DevhubAccessRequirement.Default): DevhubAccessRequirements = (read,write) match { + case (NoOne, _) => new DevhubAccessRequirements(NoOne, NoOne) + case (AdminOnly, Anyone) => new DevhubAccessRequirements(AdminOnly,AdminOnly) + case _ => new DevhubAccessRequirements(read,write) + } +} + +case class AccessRequirements(devhub: DevhubAccessRequirements) +object AccessRequirements { + final val Default = AccessRequirements(devhub = DevhubAccessRequirements.Default) +} + + +sealed trait DevhubAccessLevel { + def satisfiesRequirement(requirement: DevhubAccessRequirement): Boolean = DevhubAccessLevel.satisfies(requirement)(this) +} +object DevhubAccessLevel { + case object Developer extends DevhubAccessLevel + case object Admininstator extends DevhubAccessLevel + + import DevhubAccessRequirement._ + def satisfies(requirement: DevhubAccessRequirement)(actual: DevhubAccessLevel): Boolean = (requirement, actual) match { + case (NoOne, _) => false + case (AdminOnly, Developer) => false + case _ => true + } +} diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatters.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatters.scala index 466ef9c..c06a79c 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatters.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatters.scala @@ -25,6 +25,7 @@ import julienrf.json.derived.TypeTagSetting.ShortClassName import Types._ import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinitionType.FieldDefinitionType import Types._ +import play.api.libs.json.Json.JsValueWrapper trait NonEmptyListFormatters { @@ -43,47 +44,113 @@ trait NonEmptyListFormatters { .contramap(_.toList) } -trait JsonFormatters extends NonEmptyListFormatters { - implicit val SubscriptionFieldsIdjsonFormat = Json.valueFormat[SubscriptionFieldsId] +trait AccessRequirementsFormatters { + import DevhubAccessRequirement._ + + def ignoreDefaultField[T](value: T, default: T, jsonFieldName: String)(implicit w: Writes[T]) = + if(value == default) None else Some((jsonFieldName, Json.toJsFieldJsValueWrapper(value))) + + implicit val DevhubAccessRequirementFormat: Format[DevhubAccessRequirement] = new Format[DevhubAccessRequirement] { + + override def writes(o: DevhubAccessRequirement): JsValue = JsString(o match { + case AdminOnly => "adminOnly" + case Anyone => "anyone" + case NoOne => "noOne" + }) + + override def reads(json: JsValue): JsResult[DevhubAccessRequirement] = json match { + case JsString("adminOnly") => JsSuccess(AdminOnly) + case JsString("anyone") => JsSuccess(Anyone) + case JsString("noOne") => JsSuccess(NoOne) + case _ => JsError("Not a recognized DevhubAccessRequirement") + } + } + + implicit val DevhubAccessRequirementsReads: Reads[DevhubAccessRequirements] = ( + ((JsPath \ "read").read[DevhubAccessRequirement] or Reads.pure(DevhubAccessRequirement.Default)) and + ((JsPath \ "write").read[DevhubAccessRequirement] or Reads.pure(DevhubAccessRequirement.Default)) + )(DevhubAccessRequirements.apply _) + + implicit val DevhubAccessRequirementsWrites: OWrites[DevhubAccessRequirements] = new OWrites[DevhubAccessRequirements] { + def writes(requirements: DevhubAccessRequirements) = { + Json.obj( + ( + ignoreDefaultField(requirements.read, DevhubAccessRequirement.Default, "read") :: + ignoreDefaultField(requirements.write, DevhubAccessRequirement.Default, "write") :: + List.empty[Option[(String, JsValueWrapper)]] + ).filterNot(_.isEmpty).map(_.get): _* + ) + } + } + + implicit val AccessRequirementsReads: Reads[AccessRequirements] = Json.reads[AccessRequirements] + + implicit val AccessRequirementsWrites: Writes[AccessRequirements] = Json.writes[AccessRequirements] +} +trait JsonFormatters extends NonEmptyListFormatters with AccessRequirementsFormatters { import be.venneborg.refined.play.RefinedJsonFormats._ import eu.timepit.refined.api.Refined import eu.timepit.refined.auto._ import play.api.libs.json._ + implicit val SubscriptionFieldsIdjsonFormat = Json.valueFormat[SubscriptionFieldsId] + implicit val FieldNameFormat = formatRefined[String, FieldNameRegex, Refined] implicit val FieldsFormat: Format[Fields] = refinedMapFormat[String, FieldNameRegex, Refined] - implicit val validationRuleFormat: OFormat[ValidationRule] = derived.withTypeTag.oformat(ShortClassName) + implicit val ValidationRuleFormat: OFormat[ValidationRule] = derived.withTypeTag.oformat(ShortClassName) implicit val ValidationJF = Json.format[ValidationGroup] implicit val FieldDefinitionTypeReads = Reads.enumNameReads(FieldDefinitionType) - val fieldDefinitionReads: Reads[FieldDefinition] = ( + implicit val FieldDefinitionReads: Reads[FieldDefinition] = ( (JsPath \ "name").read[FieldName] and - (JsPath \ "description").read[String] and - ((JsPath \ "hint").read[String] or Reads.pure("")) and - (JsPath \ "type").read[FieldDefinitionType] and - ((JsPath \ "shortDescription").read[String] or Reads.pure("")) and - (JsPath \ "validation").readNullable[ValidationGroup] + (JsPath \ "description").read[String] and + ((JsPath \ "hint").read[String] or Reads.pure("")) and + (JsPath \ "type").read[FieldDefinitionType] and + ((JsPath \ "shortDescription").read[String] or Reads.pure("")) and + (JsPath \ "validation").readNullable[ValidationGroup] and + ((JsPath \ "access").read[AccessRequirements] or Reads.pure(AccessRequirements.Default)) )(FieldDefinition.apply _) - val fieldDefinitionWrites = Json.writes[FieldDefinition] - implicit val FieldDefinitionJF = Format(fieldDefinitionReads, fieldDefinitionWrites) + implicit val FieldDefinitionWrites: Writes[FieldDefinition] = new Writes[FieldDefinition] { + + def dropTail[A,B,C,D,E,F,G]( t: Tuple7[A,B,C,D,E,F,G] ): Tuple6[A,B,C,D,E,F] = (t._1, t._2, t._3, t._4, t._5, t._6) - implicit val FieldsDefinitionRequestJF = Json.format[FieldsDefinitionRequest] + // This allows us to hide default AccessRequirements from JSON - as this is a rarely used field + // but not one that business logic would want as an optional field and require getOrElse everywhere. + override def writes(o: FieldDefinition): JsValue = { + val common = + (JsPath \ "name").write[FieldName] and + (JsPath \ "description").write[String] and + (JsPath \ "hint").write[String] and + (JsPath \ "type").write[FieldDefinitionType] and + (JsPath \ "shortDescription").write[String] and + (JsPath \ "validation").writeNullable[ValidationGroup] + + (if(o.access == AccessRequirements.Default) { + (common)(unlift(FieldDefinition.unapply).andThen(dropTail)) + } else { + (common and (JsPath \ "access").write[AccessRequirements])(unlift(FieldDefinition.unapply)) + }).writes(o) + } + } + + implicit val ApiFieldDefinitionsJF: OFormat[ApiFieldDefinitions] = Json.format[ApiFieldDefinitions] + + implicit val FieldDefinitionsRequestJF = Json.format[FieldDefinitionsRequest] implicit val SubscriptionFieldsRequestJF = Json.format[SubscriptionFieldsRequest] - implicit val FieldsDefinitionResponseJF = Json.format[FieldsDefinitionResponse] - implicit val BulkFieldsDefinitionsResponseJF = Json.format[BulkFieldsDefinitionsResponse] + implicit val ApiFieldDefinitionsResponseJF = Json.format[ApiFieldDefinitionsResponse] + implicit val BulkApiFieldDefinitionsResponseJF = Json.format[BulkApiFieldDefinitionsResponse] implicit val SubscriptionFieldsResponseJF = Json.format[SubscriptionFieldsResponse] implicit val SubscriptionFieldsJF = Json.format[SubscriptionFields] implicit val BulkSubscriptionFieldsResponseJF = Json.format[BulkSubscriptionFieldsResponse] - implicit val SubsFieldValidationResponseJF: OFormat[SubsFieldValidationResponse] = derived.withTypeTag.oformat(ShortClassName) implicit val InvalidSubsFieldValidationResponseJF = Json.format[InvalidSubsFieldValidationResponse] } diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala index 4d4bb15..068a00f 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/Model.scala @@ -22,14 +22,6 @@ import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinitionType.FieldDefiniti import eu.timepit.refined._ import Types._ -case class ClientId(value: String) extends AnyVal - -case class ApiContext(value: String) extends AnyVal - -case class ApiVersion(value: String) extends AnyVal - -case class SubscriptionFieldsId(value: UUID) extends AnyVal - sealed trait ValidationRule { def validate(value: FieldValue): Boolean } @@ -54,6 +46,15 @@ object FieldDefinitionType extends Enumeration { val STRING = Value("STRING") } -case class FieldDefinition(name: FieldName, description: String, hint: String = "", `type`: FieldDefinitionType, shortDescription: String, validation: Option[ValidationGroup] = None) +case class FieldDefinition( + name: FieldName, + description: String, + hint: String = "", + `type`: FieldDefinitionType, + shortDescription: String, + validation: Option[ValidationGroup] = None, + access: AccessRequirements = AccessRequirements.Default) + +case class ApiFieldDefinitions(apiContext: String, apiVersion: String, fieldDefinitions: NEL[FieldDefinition]) case class SubscriptionFields(clientId: String, apiContext: String, apiVersion: String, fieldsId: UUID, fields: Fields) diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/Requests.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/Requests.scala index 8d7d9eb..11aef8a 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/model/Requests.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/Requests.scala @@ -21,4 +21,4 @@ import Types._ case class SubscriptionFieldsRequest(fields: Fields) -case class FieldsDefinitionRequest(fieldDefinitions: NonEmptyList[FieldDefinition]) +case class FieldDefinitionsRequest(fieldDefinitions: NonEmptyList[FieldDefinition]) diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala index a510bcc..9f07fdb 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/Responses.scala @@ -25,9 +25,9 @@ case class SubscriptionFieldsResponse(clientId: String, apiContext: String, apiV case class BulkSubscriptionFieldsResponse(subscriptions: Seq[SubscriptionFieldsResponse]) -case class FieldsDefinitionResponse(apiContext: String, apiVersion: String, fieldDefinitions: NonEmptyList[FieldDefinition]) +case class ApiFieldDefinitionsResponse(apiContext: String, apiVersion: String, fieldDefinitions: NonEmptyList[FieldDefinition]) -case class BulkFieldsDefinitionsResponse(apis: Seq[FieldsDefinitionResponse]) +case class BulkApiFieldDefinitionsResponse(apis: Seq[ApiFieldDefinitionsResponse]) sealed trait SubsFieldValidationResponse diff --git a/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinition.scala b/app/uk/gov/hmrc/apisubscriptionfields/model/Shared.scala similarity index 67% rename from app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinition.scala rename to app/uk/gov/hmrc/apisubscriptionfields/model/Shared.scala index ecc869f..3b24c7b 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinition.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/Shared.scala @@ -14,9 +14,15 @@ * limitations under the License. */ -package uk.gov.hmrc.apisubscriptionfields.repository +package uk.gov.hmrc.apisubscriptionfields.model -import uk.gov.hmrc.apisubscriptionfields.model.FieldDefinition -import cats.data.NonEmptyList +import java.util.UUID -case class FieldsDefinition(apiContext: String, apiVersion: String, fieldDefinitions: NonEmptyList[FieldDefinition]) + +case class ClientId(value: String) extends AnyVal + +case class ApiContext(value: String) extends AnyVal + +case class ApiVersion(value: String) extends AnyVal + +case class SubscriptionFieldsId(value: UUID) extends AnyVal diff --git a/app/uk/gov/hmrc/apisubscriptionfields/model/test.json b/app/uk/gov/hmrc/apisubscriptionfields/model/test.json new file mode 100644 index 0000000..b98d486 --- /dev/null +++ b/app/uk/gov/hmrc/apisubscriptionfields/model/test.json @@ -0,0 +1,11 @@ +"access": { + "devhub": { + "write" : "noOne", + "read": "adminOnly" + } + "gateKeeperAccessLevels": { + "write" : "SuperUser", + "read": "User" + } +} + diff --git a/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepository.scala b/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldDefinitionRepository.scala similarity index 62% rename from app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepository.scala rename to app/uk/gov/hmrc/apisubscriptionfields/repository/FieldDefinitionRepository.scala index 468574d..a8e0542 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepository.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/repository/FieldDefinitionRepository.scala @@ -29,25 +29,25 @@ import Types._ import scala.concurrent.Future -@ImplementedBy(classOf[FieldsDefinitionMongoRepository]) -trait FieldsDefinitionRepository { +@ImplementedBy(classOf[ApiFieldDefinitionsMongoRepository]) +trait ApiFieldDefinitionsRepository { - def save(fieldsDefinition: FieldsDefinition): Future[(FieldsDefinition, IsInsert)] + def save(definitions: ApiFieldDefinitions): Future[(ApiFieldDefinitions, IsInsert)] - def fetch(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[FieldsDefinition]] - def fetchAll(): Future[List[FieldsDefinition]] + def fetch(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[ApiFieldDefinitions]] + + def fetchAll(): Future[List[ApiFieldDefinitions]] def delete(apiContext: ApiContext, apiVersion: ApiVersion): Future[Boolean] } @Singleton -class FieldsDefinitionMongoRepository @Inject() (mongoDbProvider: MongoDbProvider) - extends ReactiveRepository[FieldsDefinition, BSONObjectID]("fieldsDefinitions", mongoDbProvider.mongo, MongoFormatters.FieldsDefinitionJF, ReactiveMongoFormats.objectIdFormats) - with FieldsDefinitionRepository - with MongoCrudHelper[FieldsDefinition] { +class ApiFieldDefinitionsMongoRepository @Inject() (mongoDbProvider: MongoDbProvider) + extends ReactiveRepository[ApiFieldDefinitions, BSONObjectID]("fieldsDefinitions", mongoDbProvider.mongo, JsonFormatters.ApiFieldDefinitionsJF, ReactiveMongoFormats.objectIdFormats) + with ApiFieldDefinitionsRepository + with MongoCrudHelper[ApiFieldDefinitions] { override val mongoCollection: JSONCollection = collection - private implicit val format = MongoFormatters.FieldsDefinitionJF override def indexes = Seq( createCompoundIndex( @@ -60,27 +60,28 @@ class FieldsDefinitionMongoRepository @Inject() (mongoDbProvider: MongoDbProvide ) ) - override def save(fieldsDefinition: FieldsDefinition): Future[(FieldsDefinition, IsInsert)] = { - save(fieldsDefinition, selectorForFieldsDefinition(fieldsDefinition)) + override def save(definitions: ApiFieldDefinitions): Future[(ApiFieldDefinitions, IsInsert)] = { + import JsonFormatters.ApiFieldDefinitionsJF + save(definitions, selectorFor(definitions)) } - override def fetch(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[FieldsDefinition]] = { - getOne(selectorForFieldsDefinition(apiContext, apiVersion)) + override def fetch(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[ApiFieldDefinitions]] = { + getOne(selectorFor(apiContext, apiVersion)) } - override def fetchAll(): Future[List[FieldsDefinition]] = { + override def fetchAll(): Future[List[ApiFieldDefinitions]] = { getMany(Json.obj()) } override def delete(apiContext: ApiContext, apiVersion: ApiVersion): Future[Boolean] = { - deleteOne(selectorForFieldsDefinition(apiContext, apiVersion)) + deleteOne(selectorFor(apiContext, apiVersion)) } - private def selectorForFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion): JsObject = { + private def selectorFor(apiContext: ApiContext, apiVersion: ApiVersion): JsObject = { selector(apiContext.value, apiVersion.value) } - private def selectorForFieldsDefinition(fd: FieldsDefinition): JsObject = { + private def selectorFor(fd: ApiFieldDefinitions): JsObject = { selector(fd.apiContext, fd.apiVersion) } diff --git a/app/uk/gov/hmrc/apisubscriptionfields/repository/MongoFormatters.scala b/app/uk/gov/hmrc/apisubscriptionfields/repository/MongoFormatters.scala deleted file mode 100644 index 3ab966a..0000000 --- a/app/uk/gov/hmrc/apisubscriptionfields/repository/MongoFormatters.scala +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020 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.repository - -import play.api.libs.json.Json -import uk.gov.hmrc.apisubscriptionfields.model.JsonFormatters - -trait MongoFormatters extends JsonFormatters { - implicit val FieldsDefinitionJF = Json.format[FieldsDefinition] -} - -object MongoFormatters extends MongoFormatters diff --git a/app/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepository.scala b/app/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepository.scala index 691c7db..992348f 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepository.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepository.scala @@ -56,7 +56,7 @@ class SubscriptionFieldsMongoRepository @Inject()(mongoDbProvider: MongoDbProvid ) with SubscriptionFieldsRepository with MongoCrudHelper[SubscriptionFields] - with MongoFormatters { + with JsonFormatters { override val mongoCollection: JSONCollection = collection diff --git a/app/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionService.scala b/app/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsService.scala similarity index 57% rename from app/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionService.scala rename to app/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsService.scala index 2933016..ad1002a 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionService.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsService.scala @@ -18,20 +18,19 @@ package uk.gov.hmrc.apisubscriptionfields.service import javax.inject.{Inject, Singleton} import uk.gov.hmrc.apisubscriptionfields.model._ -import uk.gov.hmrc.apisubscriptionfields.repository.{FieldsDefinition, FieldsDefinitionRepository} - -import scala.concurrent.ExecutionContext.Implicits.global +import Types._ import scala.concurrent.Future import cats.data.NonEmptyList -import Types._ +import scala.concurrent.ExecutionContext +import uk.gov.hmrc.apisubscriptionfields.repository.ApiFieldDefinitionsRepository @Singleton -class FieldsDefinitionService @Inject() (repository: FieldsDefinitionRepository) { +class ApiFieldDefinitionsService @Inject() (repository: ApiFieldDefinitionsRepository)(implicit ec: ExecutionContext) { - def upsert(apiContext: ApiContext, apiVersion: ApiVersion, fieldDefinitions: NonEmptyList[FieldDefinition]): Future[(FieldsDefinitionResponse, IsInsert)] = { - val fieldsDefinition = FieldsDefinition(apiContext.value, apiVersion.value, fieldDefinitions) - repository.save(fieldsDefinition).map { - case (fd: FieldsDefinition, inserted: IsInsert) => (asResponse(fd), inserted) + def upsert(apiContext: ApiContext, apiVersion: ApiVersion, fieldDefinitions: NonEmptyList[FieldDefinition]): Future[(ApiFieldDefinitionsResponse, IsInsert)] = { + val definitions = ApiFieldDefinitions(apiContext.value, apiVersion.value, fieldDefinitions) + repository.save(definitions).map { + case (fd: ApiFieldDefinitions, inserted: IsInsert) => (asResponse(fd), inserted) } } @@ -39,19 +38,19 @@ class FieldsDefinitionService @Inject() (repository: FieldsDefinitionRepository) repository.delete(apiContext, apiVersion) } - def get(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[FieldsDefinitionResponse]] = { + def get(apiContext: ApiContext, apiVersion: ApiVersion): Future[Option[ApiFieldDefinitionsResponse]] = { for { fetch <- repository.fetch(apiContext, apiVersion) } yield fetch.map(asResponse) } - def getAll: Future[BulkFieldsDefinitionsResponse] = { + def getAll: Future[BulkApiFieldDefinitionsResponse] = { (for { defs <- repository.fetchAll() - } yield defs.map(asResponse)) map (BulkFieldsDefinitionsResponse(_)) + } yield defs.map(asResponse)) map (BulkApiFieldDefinitionsResponse(_)) } - private def asResponse(fieldsDefinition: FieldsDefinition): FieldsDefinitionResponse = { - FieldsDefinitionResponse(fieldsDefinition.apiContext, fieldsDefinition.apiVersion, fieldsDefinition.fieldDefinitions) + private def asResponse(definitions: ApiFieldDefinitions): ApiFieldDefinitionsResponse = { + ApiFieldDefinitionsResponse(definitions.apiContext, definitions.apiVersion, definitions.fieldDefinitions) } } diff --git a/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala b/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala index 31d83ef..1584697 100644 --- a/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala +++ b/app/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsService.scala @@ -33,10 +33,10 @@ class UUIDCreator { } @Singleton -class SubscriptionFieldsService @Inject() (repository: SubscriptionFieldsRepository, uuidCreator: UUIDCreator, fieldsDefinitionService: FieldsDefinitionService) { +class SubscriptionFieldsService @Inject() (repository: SubscriptionFieldsRepository, uuidCreator: UUIDCreator, apiFieldDefinitionsService: ApiFieldDefinitionsService) { def validate(context: ApiContext, version: ApiVersion, fields: Fields): Future[SubsFieldValidationResponse] = { - val fieldDefinitionResponse: Future[Option[FieldsDefinitionResponse]] = fieldsDefinitionService.get(context, version) + val fieldDefinitionResponse: Future[Option[ApiFieldDefinitionsResponse]] = apiFieldDefinitionsService.get(context, version) val fieldDefinitions: Future[Option[NonEmptyList[FieldDefinition]]] = fieldDefinitionResponse.map(_.map(_.fieldDefinitions)) fieldDefinitions.map( diff --git a/conf/app.routes b/conf/app.routes index 2c5c473..537e5b9 100644 --- a/conf/app.routes +++ b/conf/app.routes @@ -1,11 +1,11 @@ # microservice-specific routes -PUT /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.FieldsDefinitionController.upsertFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) -GET /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.FieldsDefinitionController.getFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) -GET /definition uk.gov.hmrc.apisubscriptionfields.controller.FieldsDefinitionController.getAllFieldsDefinitions -DELETE /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.FieldsDefinitionController.deleteFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) +PUT /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.ApiFieldDefinitionsController.upsertFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) +GET /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.ApiFieldDefinitionsController.getFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) +GET /definition uk.gov.hmrc.apisubscriptionfields.controller.ApiFieldDefinitionsController.getAllFieldsDefinitions +DELETE /definition/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.ApiFieldDefinitionsController.deleteFieldsDefinition(apiContext: ApiContext, apiVersion: ApiVersion) -POST /validate uk.gov.hmrc.apisubscriptionfields.controller.FieldsDefinitionController.validateFieldsDefinition() +POST /validate uk.gov.hmrc.apisubscriptionfields.controller.ApiFieldDefinitionsController.validateFieldsDefinition() PUT /field/application/:clientId/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.SubscriptionFieldsController.upsertSubscriptionFields(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersion) GET /field/application/:clientId/context/:apiContext/version/:apiVersion uk.gov.hmrc.apisubscriptionfields.controller.SubscriptionFieldsController.getSubscriptionFields(clientId: ClientId, apiContext: ApiContext, apiVersion: ApiVersion) diff --git a/test/uk/gov/hmrc/apisubscriptionfields/FieldsDefinitionTestData.scala b/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala similarity index 73% rename from test/uk/gov/hmrc/apisubscriptionfields/FieldsDefinitionTestData.scala rename to test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala index e19e640..7db6248 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/FieldsDefinitionTestData.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/FieldDefinitionTestData.scala @@ -21,10 +21,11 @@ import java.util.UUID import uk.gov.hmrc.apisubscriptionfields.model._ import Types._ import cats.data.NonEmptyList -import uk.gov.hmrc.apisubscriptionfields.repository.FieldsDefinition import eu.timepit.refined.api.Refined +import uk.gov.hmrc.apisubscriptionfields.model.DevhubAccessLevel._ +import uk.gov.hmrc.apisubscriptionfields.model.DevhubAccessRequirement._ -trait FieldsDefinitionTestData extends TestData { +trait FieldDefinitionTestData extends TestData { import eu.timepit.refined.auto._ def fieldN(id: Int): FieldName = { @@ -44,10 +45,11 @@ trait FieldsDefinitionTestData extends TestData { final val FakeFieldDefinitionUrl = FieldDefinition(fieldN(1), "desc1", "hint1", FieldDefinitionType.URL, "short description", Some(FakeUrlValidation)) final val FakeFieldDefinitionUrlValidationEmpty = FieldDefinition(fieldN(1), "desc1", "hint1", FieldDefinitionType.URL, "short description", None) final val FakeFieldDefinitionString = FieldDefinition(fieldN(2), "desc2", "hint2", FieldDefinitionType.STRING, "short description", Some(FakeValidation)) + final val FakeFieldDefinitionWithAccess: FieldDefinition = FakeFieldDefinitionString.copy(validation = None, access = AccessRequirements(devhub = DevhubAccessRequirements(read = AdminOnly))) final val FakeFieldDefinitionSecureToken = FieldDefinition(fieldN(3), "desc3", "hint3", FieldDefinitionType.SECURE_TOKEN, "short description", Some(FakeValidation)) - final val FakeFieldsDefinitions = NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionUrl, FakeFieldDefinitionString, FakeFieldDefinitionSecureToken)) - final val FakeFieldsDefinition = FieldsDefinition(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions) - final val FakeFieldsDefinitionResponse = FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinition.fieldDefinitions) + final val NelOfFieldDefinitions = NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionUrl, FakeFieldDefinitionString, FakeFieldDefinitionSecureToken)) + final val FakeApiFieldDefinitions = ApiFieldDefinitions(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions) + final val FakeApiFieldDefinitionsResponse = ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, FakeApiFieldDefinitions.fieldDefinitions) final val AlphaNumericRegexRule: RegexValidationRule = RegexValidationRule("^[a-zA-Z0-9]+$") final val PasswordRegexRule: RegexValidationRule = RegexValidationRule("^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$") @@ -64,11 +66,11 @@ trait FieldsDefinitionTestData extends TestData { ) final val FakeFieldDefinitionPassword = FieldDefinition("password", "password", "this is your password", FieldDefinitionType.SECURE_TOKEN, "password", Some(FakeValidationForPassword)) - final val FakeFieldsDefinitionsWithRegex = NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionAlphnumericField, FakeFieldDefinitionPassword)) - final val FakeFieldsDefinitionWithRegex = FieldsDefinition(fakeRawContext, fakeRawVersion, FakeFieldsDefinitionsWithRegex) - final val FakeFieldsDefinitionResponseWithRegex: FieldsDefinitionResponse = FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinitionsWithRegex) + final val FakeApiFieldDefinitionssWithRegex = NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionAlphnumericField, FakeFieldDefinitionPassword)) + final val FakeApiFieldDefinitionsWithRegex = ApiFieldDefinitions(fakeRawContext, fakeRawVersion, FakeApiFieldDefinitionssWithRegex) + final val FakeApiFieldDefinitionsResponseWithRegex: ApiFieldDefinitionsResponse = ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, FakeApiFieldDefinitionssWithRegex) - final val FakeValidRegexFieldsDefinitionRequest = FieldsDefinitionRequest(NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionAlphnumericField, FakeFieldDefinitionPassword))) + final val FakeValidRegexFieldsDefinitionRequest = FieldDefinitionsRequest(NonEmptyList.fromListUnsafe(List(FakeFieldDefinitionAlphnumericField, FakeFieldDefinitionPassword))) final val jsonInvalidRegexFieldsDefinitionRequest = """{ @@ -104,8 +106,8 @@ trait FieldsDefinitionTestData extends TestData { |}""".stripMargin - def createFieldsDefinition(apiContext: String = fakeRawContext, apiVersion: String = fakeRawVersion, fieldDefinitions: NonEmptyList[FieldDefinition] = FakeFieldsDefinitions) = - FieldsDefinition(apiContext, apiVersion, fieldDefinitions) + def createApiFieldDefinitions(apiContext: String = fakeRawContext, apiVersion: String = fakeRawVersion, fieldDefinitions: NonEmptyList[FieldDefinition] = NelOfFieldDefinitions) = + ApiFieldDefinitions(apiContext, apiVersion, fieldDefinitions) def uniqueApiContext = UUID.randomUUID().toString } diff --git a/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala b/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala index 8d2f2df..30c7aa8 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/SubscriptionFieldsTestData.scala @@ -22,7 +22,7 @@ import uk.gov.hmrc.apisubscriptionfields.model._ import Types._ import scala.concurrent.Future -trait SubscriptionFieldsTestData extends FieldsDefinitionTestData with ValidationRuleTestData { +trait SubscriptionFieldsTestData extends FieldDefinitionTestData with ValidationRuleTestData { import eu.timepit.refined.auto._ final val FakeRawFieldsId = UUID.randomUUID() diff --git a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerDeleteSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerDeleteSpec.scala similarity index 77% rename from test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerDeleteSpec.scala rename to test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerDeleteSpec.scala index 03a0a61..cf3619e 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerDeleteSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerDeleteSpec.scala @@ -20,17 +20,18 @@ import org.scalamock.scalatest.MockFactory import play.api.libs.json.{JsDefined, JsString} import play.api.test.{FakeRequest, StubControllerComponentsFactory} import play.api.test.Helpers._ -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData import uk.gov.hmrc.apisubscriptionfields.model.JsonFormatters -import uk.gov.hmrc.apisubscriptionfields.service.FieldsDefinitionService +import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService import uk.gov.hmrc.play.test.UnitSpec import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global -class FieldsDefinitionControllerDeleteSpec extends UnitSpec with FieldsDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { +class ApiFieldDefinitionsControllerDeleteSpec extends UnitSpec with FieldDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { - private val mockFieldsDefinitionService = mock[FieldsDefinitionService] - private val controller = new FieldsDefinitionController(stubControllerComponents(), mockFieldsDefinitionService) + private val mockFieldsDefinitionService = mock[ApiFieldDefinitionsService] + private val controller = new ApiFieldDefinitionsController(stubControllerComponents(), mockFieldsDefinitionService) "DELETE /definition/context/:apiContext/version/:apiVersion" should { "return NO_CONTENT (204) when successfully deleted from repo" in { diff --git a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerGetSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerGetSpec.scala similarity index 86% rename from test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerGetSpec.scala rename to test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerGetSpec.scala index c6060f8..6f0567f 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerGetSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerGetSpec.scala @@ -20,17 +20,19 @@ import org.scalamock.scalatest.MockFactory import play.api.libs.json.{JsDefined, JsString, Json} import play.api.test.Helpers._ import play.api.test._ -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData -import uk.gov.hmrc.apisubscriptionfields.model.{BulkFieldsDefinitionsResponse, FieldsDefinitionResponse, JsonFormatters} -import uk.gov.hmrc.apisubscriptionfields.service.FieldsDefinitionService +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.model.{BulkApiFieldDefinitionsResponse, ApiFieldDefinitionsResponse, JsonFormatters} +import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService import uk.gov.hmrc.play.test.UnitSpec import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global +import uk.gov.hmrc.apisubscriptionfields.model.ApiFieldDefinitionsResponse -class FieldsDefinitionControllerGetSpec extends UnitSpec with FieldsDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { +class ApiFieldDefinitionsControllerGetSpec extends UnitSpec with FieldDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { - private val mockFieldsDefinitionService = mock[FieldsDefinitionService] - private val controller = new FieldsDefinitionController(stubControllerComponents(), mockFieldsDefinitionService) + private val mockFieldsDefinitionService = mock[ApiFieldDefinitionsService] + private val controller = new ApiFieldDefinitionsController(stubControllerComponents(), mockFieldsDefinitionService) private val responseJsonString = """{ @@ -69,7 +71,7 @@ class FieldsDefinitionControllerGetSpec extends UnitSpec with FieldsDefinitionTe | ] |}""".stripMargin private val responseJson = Json.parse(responseJsonString) - private val responseModel = responseJson.as[FieldsDefinitionResponse] + private val responseModel = responseJson.as[ApiFieldDefinitionsResponse] private val allResponseJsonString = """{ @@ -147,8 +149,8 @@ class FieldsDefinitionControllerGetSpec extends UnitSpec with FieldsDefinitionTe | ] |}""".stripMargin private val allResponseJson = Json.parse(allResponseJsonString) - private val allResponseModel = allResponseJson.as[BulkFieldsDefinitionsResponse] - private val emptyAllResponseJson = Json.toJson(BulkFieldsDefinitionsResponse(Seq())) + private val allResponseModel = allResponseJson.as[BulkApiFieldDefinitionsResponse] + private val emptyAllResponseJson = Json.toJson(BulkApiFieldDefinitionsResponse(Seq())) "GET /definition/context/:apiContext/version/:apiVersion" should { "return OK when the expected record exists in the repo" in { @@ -192,7 +194,7 @@ class FieldsDefinitionControllerGetSpec extends UnitSpec with FieldsDefinitionTe } "return OK with an empty list when no field definitions exist in the repo" in { - mockFieldsDefinitionService.getAll _ expects () returns Future.successful(BulkFieldsDefinitionsResponse(Seq())) + mockFieldsDefinitionService.getAll _ expects () returns Future.successful(BulkApiFieldDefinitionsResponse(Seq())) val result = await(controller.getAllFieldsDefinitions(FakeRequest())) diff --git a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPostSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPostSpec.scala similarity index 74% rename from test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPostSpec.scala rename to test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPostSpec.scala index 780068d..d36440e 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPostSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPostSpec.scala @@ -21,20 +21,21 @@ import play.api.libs.json.{JsValue, Json} import play.api.mvc._ import play.api.test.Helpers._ import play.api.test._ -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData -import uk.gov.hmrc.apisubscriptionfields.model.{FieldsDefinitionRequest, JsonFormatters} -import uk.gov.hmrc.apisubscriptionfields.service.FieldsDefinitionService +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.model.{FieldDefinitionsRequest, JsonFormatters} +import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService import uk.gov.hmrc.play.test.UnitSpec import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global -class FieldsDefinitionControllerPostSpec extends UnitSpec -with FieldsDefinitionTestData +class ApiFieldDefinitionsControllerPostSpec extends UnitSpec +with FieldDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { - private val mockFieldDefintionService = mock[FieldsDefinitionService] - private val controller = new FieldsDefinitionController(stubControllerComponents(), mockFieldDefintionService) + private val mockFieldDefintionService = mock[ApiFieldDefinitionsService] + private val controller = new ApiFieldDefinitionsController(stubControllerComponents(), mockFieldDefintionService) "validateFieldsDefinition" should { "return OK when FieldDefinitionsRequest is valid" in { @@ -65,6 +66,6 @@ with StubControllerComponentsFactory { FakeRequest() .withJsonBody(jsonBody).map(r => r.json) - private def mkJson(model: FieldsDefinitionRequest) = Json.toJson(model)(Json.writes[FieldsDefinitionRequest]) + private def mkJson(model: FieldDefinitionsRequest) = Json.toJson(model)(Json.writes[FieldDefinitionsRequest]) } diff --git a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPutSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPutSpec.scala similarity index 62% rename from test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPutSpec.scala rename to test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPutSpec.scala index 77f1b37..5848abd 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/controller/FieldsDefinitionControllerPutSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/controller/ApiFieldDefinitionsControllerPutSpec.scala @@ -21,40 +21,41 @@ import play.api.libs.json.{JsValue, Json} import play.api.mvc._ import play.api.test.Helpers._ import play.api.test._ -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData -import uk.gov.hmrc.apisubscriptionfields.model.{FieldsDefinitionRequest, JsonFormatters} -import uk.gov.hmrc.apisubscriptionfields.service.FieldsDefinitionService +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.model.{FieldDefinitionsRequest, JsonFormatters} +import uk.gov.hmrc.apisubscriptionfields.service.ApiFieldDefinitionsService import uk.gov.hmrc.play.test.UnitSpec +import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future -class FieldsDefinitionControllerPutSpec extends UnitSpec - with FieldsDefinitionTestData +class ApiFieldDefinitionsControllerPutSpec extends UnitSpec + with FieldDefinitionTestData with MockFactory with JsonFormatters with StubControllerComponentsFactory { - private val mockFieldsDefinitionService = mock[FieldsDefinitionService] - private val controller = new FieldsDefinitionController(stubControllerComponents(), mockFieldsDefinitionService) + private val mockApiFieldDefinitionsService = mock[ApiFieldDefinitionsService] + private val controller = new ApiFieldDefinitionsController(stubControllerComponents(), mockApiFieldDefinitionsService) "PUT /definition/context/:apiContext/version/:apiVersion" should { "return CREATED when created in the repo" in { - (mockFieldsDefinitionService.upsert _). - expects(FakeContext, FakeVersion, FakeFieldsDefinitions). - returns(Future.successful((FakeFieldsDefinitionResponse, true))) + (mockApiFieldDefinitionsService.upsert _). + expects(FakeContext, FakeVersion, NelOfFieldDefinitions). + returns(Future.successful((FakeApiFieldDefinitionsResponse, true))) - val json = mkJson(FieldsDefinitionRequest(FakeFieldsDefinitions)) + val json = mkJson(FieldDefinitionsRequest(NelOfFieldDefinitions)) testSubmitResult(mkRequest(json)) { result => status(result) shouldBe CREATED } } "return OK when updated in the repo" in { - (mockFieldsDefinitionService.upsert _). - expects(FakeContext, FakeVersion, FakeFieldsDefinitions). - returns(Future.successful((FakeFieldsDefinitionResponse, false))) + (mockApiFieldDefinitionsService.upsert _). + expects(FakeContext, FakeVersion, NelOfFieldDefinitions). + returns(Future.successful((FakeApiFieldDefinitionsResponse, false))) - val json = mkJson(FieldsDefinitionRequest(FakeFieldsDefinitions)) + val json = mkJson(FieldDefinitionsRequest(NelOfFieldDefinitions)) testSubmitResult(mkRequest(json)) { result => status(result) shouldBe OK } @@ -78,5 +79,5 @@ class FieldsDefinitionControllerPutSpec extends UnitSpec FakeRequest() .withJsonBody(jsonBody).map(r => r.json) - private def mkJson(model: FieldsDefinitionRequest) = Json.toJson(model)(Json.writes[FieldsDefinitionRequest]) + private def mkJson(model: FieldDefinitionsRequest) = Json.toJson(model)(Json.writes[FieldDefinitionsRequest]) } diff --git a/test/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirementsSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirementsSpec.scala new file mode 100644 index 0000000..4448cb0 --- /dev/null +++ b/test/uk/gov/hmrc/apisubscriptionfields/model/AccessRequirementsSpec.scala @@ -0,0 +1,95 @@ +/* + * Copyright 2020 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.model + +import org.scalatest.WordSpec +import org.scalatest.Matchers +import uk.gov.hmrc.apisubscriptionfields.model.DevhubAccessLevel._ +import uk.gov.hmrc.apisubscriptionfields.model.DevhubAccessRequirement._ + +class AccessRequirementsSpec extends WordSpec with Matchers { + + "DevhubRequirement" should { + + "Developer" should { + "satisfy the Anyone requirement" in { + Developer.satisfiesRequirement(Anyone) shouldBe true + } + "not satisfy the AdminOnly requirement" in { + Developer.satisfiesRequirement(AdminOnly) shouldBe false + } + "not satisfy the NoOne requirement" in { + Developer.satisfiesRequirement(NoOne) shouldBe false + } + } + + "Admin" should { + "satisfy the Anyone requirement" in { + Admininstator.satisfiesRequirement(Anyone) shouldBe true + } + "satisfy the AdminOnly requirement" in { + Admininstator.satisfiesRequirement(AdminOnly) shouldBe true + } + "not satisfy the NoOne requirement" in { + Admininstator.satisfiesRequirement(NoOne) shouldBe false + } + } + } + + "DevhubAccessRequirements" should { + + "a producer team wants to restrict collaborators to only view but not change a field" in { + val dar = DevhubAccessRequirements(read = DevhubAccessRequirement.Default, write = NoOne) + + dar.satisfiesRead(Developer) shouldBe true + dar.satisfiesRead(Admininstator) shouldBe true + + dar.satisfiesWrite(Developer) shouldBe false + dar.satisfiesWrite(Admininstator) shouldBe false + } + + "a producer team wants to restrict Developers from even viewing a field but allow administrators to read and write" in { + val dar = DevhubAccessRequirements(read = AdminOnly, write = AdminOnly) + + dar.satisfiesRead(Developer) shouldBe false + dar.satisfiesWrite(Developer) shouldBe false + + dar.satisfiesRead(Admininstator) shouldBe true + dar.satisfiesWrite(Admininstator) shouldBe true + } + + "a producer team wants to restrict Developers to viewing a field but allow administrators to read and write" in { + val dar = DevhubAccessRequirements(read = Anyone, write = AdminOnly) + + dar.satisfiesRead(Developer) shouldBe true + dar.satisfiesWrite(Developer) shouldBe false + + dar.satisfiesRead(Admininstator) shouldBe true + dar.satisfiesWrite(Admininstator) shouldBe true + } + + "a producer team wants to allow anyone to view and change a field" in { + val dar = DevhubAccessRequirements(read = Anyone) + + dar.satisfiesRead(Developer) shouldBe true + dar.satisfiesWrite(Developer) shouldBe true + + dar.satisfiesRead(Admininstator) shouldBe true + dar.satisfiesWrite(Admininstator) shouldBe true + } + } +} diff --git a/test/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatterSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatterSpec.scala index f7bc375..226880f 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatterSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/model/JsonFormatterSpec.scala @@ -18,9 +18,9 @@ package uk.gov.hmrc.apisubscriptionfields.model import cats.data.NonEmptyList import org.scalatest.{Matchers, WordSpec} -import uk.gov.hmrc.apisubscriptionfields.{FieldsDefinitionTestData, SubscriptionFieldsTestData} +import uk.gov.hmrc.apisubscriptionfields.{FieldDefinitionTestData, SubscriptionFieldsTestData} -class JsonFormatterSpec extends WordSpec with Matchers with JsonFormatters with SubscriptionFieldsTestData with FieldsDefinitionTestData { +class JsonFormatterSpec extends WordSpec with Matchers with JsonFormatters with SubscriptionFieldsTestData with FieldDefinitionTestData { import play.api.libs.json._ @@ -28,9 +28,9 @@ class JsonFormatterSpec extends WordSpec with Matchers with JsonFormatters with private val subscriptionFieldsResponse = SubscriptionFieldsResponse(fakeRawClientId, fakeRawContext, fakeRawVersion, FakeFieldsId, fakeFields) private val bulkSubscriptionFieldsResponse = BulkSubscriptionFieldsResponse(Seq(subscriptionFieldsResponse)) - private val fakeFieldsDefinitionResponse = FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrl)) - private val fakeFieldsDefinitionResponseEmptyValidation = FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrlValidationEmpty)) - private val bulkFieldsDefinitionResponse = BulkFieldsDefinitionsResponse(Seq(fakeFieldsDefinitionResponse)) + private val fakeApiFieldDefinitionsResponse = ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrl)) + private val fakeApiFieldDefinitionsResponseEmptyValidation = ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrlValidationEmpty)) + private val bulkFieldsDefinitionResponse = BulkApiFieldDefinitionsResponse(Seq(fakeApiFieldDefinitionsResponse)) private def objectAsJsonString[A](a: A)(implicit t: Writes[A]) = Json.asciiStringify(Json.toJson(a)) @@ -54,6 +54,30 @@ class JsonFormatterSpec extends WordSpec with Matchers with JsonFormatters with } } + "ApiFieldDefinitionsResponse" should { + "marshal json" in { + objectAsJsonString(fakeApiFieldDefinitionsResponse) shouldBe fieldDefinitionJson + } + + "marshal json when ValidationGroup is empty" in { + objectAsJsonString(fakeApiFieldDefinitionsResponseEmptyValidation) shouldBe fieldDefinitionEmptyValidationJson + } + + "unmarshal text" in { + Json.parse(fieldDefinitionJson).validate[ApiFieldDefinitionsResponse] match { + case JsSuccess(r, _) => r shouldBe fakeApiFieldDefinitionsResponse + case JsError(e) => fail(s"Should have parsed json text but got $e") + } + } + + "unmarshal text when ValidationGroup is empty" in { + Json.parse(fieldDefinitionEmptyValidationJson).validate[ApiFieldDefinitionsResponse] match { + case JsSuccess(r, _) => r shouldBe fakeApiFieldDefinitionsResponseEmptyValidation + case JsError(e) => fail(s"Should have parsed json text but got $e") + } + } + } + "BulkSubscriptionFieldsResponse" should { val json = s"""{"subscriptions":[$subscriptionFieldJson]}""" @@ -69,42 +93,98 @@ class JsonFormatterSpec extends WordSpec with Matchers with JsonFormatters with } } - "FieldsDefinitionResponse" should { - "marshal json" in { - objectAsJsonString(fakeFieldsDefinitionResponse) shouldBe fieldDefinitionJson - } + "BulkApiFieldDefinitionsResponse" should { + val json = s"""{"apis":[$fieldDefinitionJson]}""" - "marshal json when ValidationGroup is empty" in { - objectAsJsonString(fakeFieldsDefinitionResponseEmptyValidation) shouldBe fieldDefinitionEmptyValidationJson + "marshal json" in { + objectAsJsonString(bulkFieldsDefinitionResponse) shouldBe json } "unmarshal text" in { - Json.parse(fieldDefinitionJson).validate[FieldsDefinitionResponse] match { - case JsSuccess(r, _) => r shouldBe fakeFieldsDefinitionResponse + Json.parse(json).validate[BulkApiFieldDefinitionsResponse] match { + case JsSuccess(r, _) => r shouldBe bulkFieldsDefinitionResponse case JsError(e) => fail(s"Should have parsed json text but got $e") } } + } + + "DevhubAccessRequirements" should { + import DevhubAccessRequirement._ + + "marshall a default correctly" in { + val rq = DevhubAccessRequirements.Default + + Json.stringify(Json.toJson(rq)) shouldBe "{}" + } - "unmarshal text when ValidationGroup is empty" in { - Json.parse(fieldDefinitionEmptyValidationJson).validate[FieldsDefinitionResponse] match { - case JsSuccess(r, _) => r shouldBe fakeFieldsDefinitionResponseEmptyValidation - case JsError(e) => fail(s"Should have parsed json text but got $e") - } + "marshall a read option" in { + val rq = DevhubAccessRequirements(read = AdminOnly) + + Json.stringify(Json.toJson(rq)) shouldBe """{"read":"adminOnly","write":"adminOnly"}""" + } + + "marshall a write option" in { + val rq = DevhubAccessRequirements(read = DevhubAccessRequirement.Default, write = NoOne) + + Json.stringify(Json.toJson(rq)) shouldBe """{"write":"noOne"}""" + } + + "marshall a complete option" in { + val rq = DevhubAccessRequirements(read = AdminOnly, write = NoOne) + + Json.stringify(Json.toJson(rq)) shouldBe """{"read":"adminOnly","write":"noOne"}""" + } + + "unmarshall a default correctly" in { + Json.fromJson[DevhubAccessRequirements](Json.parse("{}")) shouldBe JsSuccess(DevhubAccessRequirements.Default) + } + + "unmarshall a read correctly" in { + Json.fromJson[DevhubAccessRequirements](Json.parse("""{"read":"adminOnly"}""")) shouldBe JsSuccess(DevhubAccessRequirements(read = AdminOnly, write = AdminOnly)) + } + + "unmarshall a write correctly" in { + Json.fromJson[DevhubAccessRequirements](Json.parse("""{"write":"noOne"}""")) shouldBe JsSuccess(DevhubAccessRequirements(read = Anyone, write = NoOne)) + } + + "unmarshall a complete option correctly" in { + Json.fromJson[DevhubAccessRequirements](Json.parse("""{"read":"adminOnly","write":"noOne"}""")) shouldBe JsSuccess(DevhubAccessRequirements(read = AdminOnly, write = NoOne)) } } - "BulkFieldsDefinitionsResponse" should { - val json = s"""{"apis":[$fieldDefinitionJson]}""" + "AccessRequirements" should { + import DevhubAccessRequirement._ - "marshal json" in { - objectAsJsonString(bulkFieldsDefinitionResponse) shouldBe json + "marshalling a default correctly" in { + val rq = AccessRequirements.Default + + Json.stringify(Json.toJson(rq)) shouldBe """{"devhub":{}}""" } - "unmarshal text" in { - Json.parse(json).validate[BulkFieldsDefinitionsResponse] match { - case JsSuccess(r, _) => r shouldBe bulkFieldsDefinitionResponse - case JsError(e) => fail(s"Should have parsed json text but got $e") - } + "marshalling with some devhub requirements correctly" in { + // read is set explicity, but write will be given this greater restriction too. + val rq = AccessRequirements(devhub = DevhubAccessRequirements.apply(read = AdminOnly)) + + Json.stringify(Json.toJson(rq)) shouldBe """{"devhub":{"read":"adminOnly","write":"adminOnly"}}""" + } + + "unmarshall with default correctly" in { + Json.fromJson[AccessRequirements](Json.parse("""{"devhub":{}}""")) shouldBe JsSuccess(AccessRequirements.Default) + } + + "unmarshall with non default correctly" in { + Json.fromJson[AccessRequirements](Json.parse("""{"devhub":{"read":"adminOnly"}}""")) shouldBe JsSuccess(AccessRequirements(devhub = DevhubAccessRequirements(read = AdminOnly))) + } + } + + "FieldDefinition" should { + "marshal json with non default access" in { + objectAsJsonString(FakeFieldDefinitionWithAccess) should include(""","access":{"devhub":{"read":"adminOnly","write":"adminOnly"}}""") + } + + "marshal json without mention of default access" in { + objectAsJsonString(FakeFieldDefinitionWithAccess.copy(access = AccessRequirements.Default)) should not include(""""access":{"devhub":{"read":"adminOnly", "write":"adminOnly"}}""") + objectAsJsonString(FakeFieldDefinitionWithAccess.copy(access = AccessRequirements.Default)) should not include(""""access"""") } } } diff --git a/test/uk/gov/hmrc/apisubscriptionfields/model/ModelSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/model/ModelSpec.scala index 5340dd3..1d87086 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/model/ModelSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/model/ModelSpec.scala @@ -18,10 +18,10 @@ package uk.gov.hmrc.apisubscriptionfields.model import uk.gov.hmrc.play.test.UnitSpec import uk.gov.hmrc.apisubscriptionfields.SubscriptionFieldsTestData -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData -class ModelSpec extends UnitSpec with SubscriptionFieldsTestData with FieldsDefinitionTestData with ValidationRuleTestData { +class ModelSpec extends UnitSpec with SubscriptionFieldsTestData with FieldDefinitionTestData with ValidationRuleTestData { "RegexValidationRule" should { "return true when the value is valid - correct case" in { diff --git a/test/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepositorySpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/repository/ApiFieldDefinitionsRepositorySpec.scala similarity index 67% rename from test/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepositorySpec.scala rename to test/uk/gov/hmrc/apisubscriptionfields/repository/ApiFieldDefinitionsRepositorySpec.scala index 3ce1d76..85f0d03 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/repository/FieldsDefinitionRepositorySpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/repository/ApiFieldDefinitionsRepositorySpec.scala @@ -20,27 +20,26 @@ import org.scalamock.scalatest.MockFactory import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach} import reactivemongo.api.DB import reactivemongo.bson.BSONDocument -import uk.gov.hmrc.apisubscriptionfields.model.{ApiContext, ApiVersion, JsonFormatters} -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.model.{ApiContext, ApiVersion, ApiFieldDefinitions, JsonFormatters} +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData import uk.gov.hmrc.mongo.MongoSpecSupport import uk.gov.hmrc.play.test.UnitSpec import scala.concurrent.ExecutionContext.Implicits.global -class FieldsDefinitionRepositorySpec extends UnitSpec +class ApiFieldDefinitionsRepositorySpec extends UnitSpec with BeforeAndAfterAll with BeforeAndAfterEach with MongoSpecSupport - with MongoFormatters with JsonFormatters - with FieldsDefinitionTestData + with FieldDefinitionTestData with MockFactory { self => private val mongoDbProvider = new MongoDbProvider { override val mongo: () => DB = self.mongo } - private val repository = new FieldsDefinitionMongoRepository(mongoDbProvider) + private val repository = new ApiFieldDefinitionsMongoRepository(mongoDbProvider) override def beforeEach() { super.beforeEach() @@ -56,10 +55,10 @@ class FieldsDefinitionRepositorySpec extends UnitSpec await(repository.collection.count()) } - private def createFieldsDefinition = FieldsDefinition(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions) + private def createApiFieldDefinitions = ApiFieldDefinitions(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions) private trait Setup { - val fieldsDefinition: FieldsDefinition = createFieldsDefinition + val definitions: ApiFieldDefinitions = createApiFieldDefinitions } "save" should { @@ -68,28 +67,28 @@ class FieldsDefinitionRepositorySpec extends UnitSpec "insert the record in the collection" in new Setup { collectionSize shouldBe 0 - await(repository.save(fieldsDefinition)) shouldBe ((fieldsDefinition, true)) + await(repository.save(definitions)) shouldBe ((definitions, true)) collectionSize shouldBe 1 - await(repository.collection.find(selector(fieldsDefinition)).one[FieldsDefinition]) shouldBe Some(fieldsDefinition) + await(repository.collection.find(selector(definitions)).one[ApiFieldDefinitions]) shouldBe Some(definitions) } "update the record in the collection" in new Setup { collectionSize shouldBe 0 - await(repository.save(fieldsDefinition)) shouldBe ((fieldsDefinition, true)) + await(repository.save(definitions)) shouldBe ((definitions, true)) collectionSize shouldBe 1 - val edited = fieldsDefinition.copy(fieldDefinitions = FakeFieldsDefinitions) + val edited = definitions.copy(fieldDefinitions = NelOfFieldDefinitions) await(repository.save(edited)) shouldBe ((edited, false)) collectionSize shouldBe 1 - await(repository.collection.find(selector(edited)).one[FieldsDefinition]) shouldBe Some(edited) + await(repository.collection.find(selector(edited)).one[ApiFieldDefinitions]) shouldBe Some(edited) } } "fetchAll" should { "retrieve all the field definitions from the collection" in { - val fieldsDefinition1 = createFieldsDefinition(apiContext = uniqueApiContext) - val fieldsDefinition2 = createFieldsDefinition(apiContext = uniqueApiContext) + val fieldsDefinition1 = createApiFieldDefinitions(apiContext = uniqueApiContext) + val fieldsDefinition2 = createApiFieldDefinitions(apiContext = uniqueApiContext) await(repository.save(fieldsDefinition1)) await(repository.save(fieldsDefinition2)) collectionSize shouldBe 2 @@ -104,16 +103,16 @@ class FieldsDefinitionRepositorySpec extends UnitSpec "fetch" should { "retrieve the correct record from the fields definition" in new Setup { - await(repository.save(fieldsDefinition)) + await(repository.save(definitions)) collectionSize shouldBe 1 - await(repository.fetch(FakeContext, FakeVersion)) shouldBe Some(fieldsDefinition) + await(repository.fetch(FakeContext, FakeVersion)) shouldBe Some(definitions) } "return `None` when the `id` doesn't match any record in the collection" in { for (i <- 1 to 3) { - val fieldsDefinition = createFieldsDefinition(apiContext = uniqueApiContext) - await(repository.save(fieldsDefinition)) + val definitions = createApiFieldDefinitions(apiContext = uniqueApiContext) + await(repository.save(definitions)) } collectionSize shouldBe 3 @@ -123,17 +122,17 @@ class FieldsDefinitionRepositorySpec extends UnitSpec "delete" should { "remove the record with a specific fields definition" in { - val fieldsDefinition = createFieldsDefinition + val definitions = createApiFieldDefinitions - await(repository.save(fieldsDefinition)) + await(repository.save(definitions)) collectionSize shouldBe 1 - await(repository.delete(ApiContext(fieldsDefinition.apiContext), ApiVersion(fieldsDefinition.apiVersion))) shouldBe true + await(repository.delete(ApiContext(definitions.apiContext), ApiVersion(definitions.apiVersion))) shouldBe true collectionSize shouldBe 0 } "not alter the collection for unknown fields definition" in { - await(repository.save(createFieldsDefinition)) + await(repository.save(createApiFieldDefinitions)) collectionSize shouldBe 1 await(repository.delete(ApiContext("DOES_NOT_EXIST"), FakeVersion)) shouldBe false @@ -144,15 +143,15 @@ class FieldsDefinitionRepositorySpec extends UnitSpec "collection" should { "have a unique compound index based on `apiContext` and `apiVersion`" in new Setup { - await(repository.save(fieldsDefinition)) + await(repository.save(definitions)) collectionSize shouldBe 1 - await(repository.save(fieldsDefinition)) + await(repository.save(definitions)) collectionSize shouldBe 1 } } - private def selector(fd: FieldsDefinition) = { + private def selector(fd: ApiFieldDefinitions) = { BSONDocument("apiContext" -> fd.apiContext, "apiVersion" -> fd.apiVersion) } } diff --git a/test/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepositorySpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepositorySpec.scala index a3c55c6..70b6191 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepositorySpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/repository/SubscriptionFieldsRepositorySpec.scala @@ -35,7 +35,6 @@ class SubscriptionFieldsRepositorySpec extends UnitSpec with BeforeAndAfterAll with BeforeAndAfterEach with MongoSpecSupport - with MongoFormatters with JsonFormatters with SubscriptionFieldsTestData with MockFactory { self => diff --git a/test/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsServiceSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsServiceSpec.scala new file mode 100644 index 0000000..7a9df2e --- /dev/null +++ b/test/uk/gov/hmrc/apisubscriptionfields/service/ApiFieldDefinitionsServiceSpec.scala @@ -0,0 +1,122 @@ +/* + * Copyright 2020 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.service + +import org.scalamock.scalatest.MockFactory +import uk.gov.hmrc.apisubscriptionfields.FieldDefinitionTestData +import uk.gov.hmrc.apisubscriptionfields.model.{ApiContext, ApiVersion, ApiFieldDefinitions, BulkApiFieldDefinitionsResponse, ApiFieldDefinitionsResponse} +import uk.gov.hmrc.apisubscriptionfields.repository.ApiFieldDefinitionsRepository +import uk.gov.hmrc.play.test.UnitSpec + +import scala.concurrent.Future +import cats.data.NonEmptyList +import scala.concurrent.ExecutionContext.Implicits.global + +class ApiFieldDefinitionsServiceSpec extends UnitSpec with FieldDefinitionTestData with MockFactory { + + private val mockApiFieldDefinitionsRepository = mock[ApiFieldDefinitionsRepository] + private val service = new ApiFieldDefinitionsService(mockApiFieldDefinitionsRepository) + + "getAll" should { + "return an empty list when there are no records in the database collection" in { + (mockApiFieldDefinitionsRepository.fetchAll _).expects().returns(List()) + + val result = await(service.getAll) + + result shouldBe BulkApiFieldDefinitionsResponse(List()) + } + + "return a list of all entries" in { + val fd1 = createApiFieldDefinitions(apiContext = "api-1", fieldDefinitions = NonEmptyList.one(FakeFieldDefinitionUrl)) + val fd2 = createApiFieldDefinitions(apiContext = "api-2", fieldDefinitions = NonEmptyList.one(FakeFieldDefinitionString)) + + (mockApiFieldDefinitionsRepository.fetchAll _).expects().returns(List(fd1, fd2)) + + val result = await(service.getAll) + + val expectedResponse = BulkApiFieldDefinitionsResponse(apis = Seq( + ApiFieldDefinitionsResponse("api-1", fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrl)), + ApiFieldDefinitionsResponse("api-2", fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionString)))) + result shouldBe expectedResponse + } + } + + "get" should { + "return None when no definition exists in the database collection" in { + (mockApiFieldDefinitionsRepository fetch(_: ApiContext, _: ApiVersion)).expects(FakeContext, FakeVersion) + .returns(None) + + val result = await(service.get(FakeContext, FakeVersion)) + + result shouldBe None + } + + "return the expected definition" in { + (mockApiFieldDefinitionsRepository fetch(_: ApiContext, _: ApiVersion)).expects(FakeContext, FakeVersion) + .returns(Some(FakeApiFieldDefinitions)) + + val result = await(service.get(FakeContext, FakeVersion)) + + result shouldBe Some(FakeApiFieldDefinitionsResponse) + } + } + + "upsert" should { + "return false when updating an existing fields definition" in { + (mockApiFieldDefinitionsRepository save _) expects FakeApiFieldDefinitions returns ((FakeApiFieldDefinitions, false)) + + val result = await(service.upsert(FakeContext, FakeVersion, NelOfFieldDefinitions)) + + result shouldBe ((ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions), false)) + } + + "return true when creating a new fields definition" in { + (mockApiFieldDefinitionsRepository save _) expects FakeApiFieldDefinitions returns ((FakeApiFieldDefinitions, true)) + + val result = await(service.upsert(FakeContext, FakeVersion, NelOfFieldDefinitions)) + + result shouldBe ((ApiFieldDefinitionsResponse(fakeRawContext, fakeRawVersion, NelOfFieldDefinitions), true)) + } + + "propagate the error" in { + (mockApiFieldDefinitionsRepository save(_: ApiFieldDefinitions)) expects * returns Future.failed(emulatedFailure) + + val caught = intercept[EmulatedFailure] { + await(service.upsert(FakeContext, FakeVersion, NelOfFieldDefinitions)) + } + + caught shouldBe emulatedFailure + } + } + + "delete" should { + "return true when the record is removed from the database collection" in { + (mockApiFieldDefinitionsRepository delete (_:ApiContext, _:ApiVersion)).expects(FakeContext, FakeVersion) + .returns(true) + + await(service.delete(FakeContext, FakeVersion)) shouldBe true + } + + "return false when the record is not found in the database collection" in { + (mockApiFieldDefinitionsRepository delete (_:ApiContext, _:ApiVersion)).expects(FakeContext, FakeVersion) + .returns(false) + + await(service.delete(FakeContext, FakeVersion)) shouldBe false + } + } + +} diff --git a/test/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionServiceSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionServiceSpec.scala deleted file mode 100644 index 0d5200e..0000000 --- a/test/uk/gov/hmrc/apisubscriptionfields/service/FieldsDefinitionServiceSpec.scala +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2020 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.service - -import org.scalamock.scalatest.MockFactory -import uk.gov.hmrc.apisubscriptionfields.FieldsDefinitionTestData -import uk.gov.hmrc.apisubscriptionfields.model.{ApiContext, ApiVersion, BulkFieldsDefinitionsResponse, FieldsDefinitionResponse} -import uk.gov.hmrc.apisubscriptionfields.repository.{FieldsDefinition, FieldsDefinitionRepository} -import uk.gov.hmrc.play.test.UnitSpec - -import scala.concurrent.Future -import cats.data.NonEmptyList - -class FieldsDefinitionServiceSpec extends UnitSpec with FieldsDefinitionTestData with MockFactory { - - private val mockFieldsDefinitionRepository = mock[FieldsDefinitionRepository] - private val service = new FieldsDefinitionService(mockFieldsDefinitionRepository) - - "getAll" should { - "return an empty list when there are no records in the database collection" in { - (mockFieldsDefinitionRepository.fetchAll _).expects().returns(List()) - - val result = await(service.getAll) - - result shouldBe BulkFieldsDefinitionsResponse(List()) - } - - "return a list of all entries" in { - val fd1 = createFieldsDefinition(apiContext = "api-1", fieldDefinitions = NonEmptyList.one(FakeFieldDefinitionUrl)) - val fd2 = createFieldsDefinition(apiContext = "api-2", fieldDefinitions = NonEmptyList.one(FakeFieldDefinitionString)) - - (mockFieldsDefinitionRepository.fetchAll _).expects().returns(List(fd1, fd2)) - - val result = await(service.getAll) - - val expectedResponse = BulkFieldsDefinitionsResponse(apis = Seq( - FieldsDefinitionResponse("api-1", fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionUrl)), - FieldsDefinitionResponse("api-2", fakeRawVersion, NonEmptyList.one(FakeFieldDefinitionString)))) - result shouldBe expectedResponse - } - } - - "get" should { - "return None when no definition exists in the database collection" in { - (mockFieldsDefinitionRepository fetch(_: ApiContext, _: ApiVersion)).expects(FakeContext, FakeVersion) - .returns(None) - - val result = await(service.get(FakeContext, FakeVersion)) - - result shouldBe None - } - - "return the expected definition" in { - (mockFieldsDefinitionRepository fetch(_: ApiContext, _: ApiVersion)).expects(FakeContext, FakeVersion) - .returns(Some(FakeFieldsDefinition)) - - val result = await(service.get(FakeContext, FakeVersion)) - - result shouldBe Some(FakeFieldsDefinitionResponse) - } - } - - "upsert" should { - "return false when updating an existing fields definition" in { - (mockFieldsDefinitionRepository save _) expects FakeFieldsDefinition returns ((FakeFieldsDefinition, false)) - - val result = await(service.upsert(FakeContext, FakeVersion, FakeFieldsDefinitions)) - - result shouldBe ((FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions), false)) - } - - "return true when creating a new fields definition" in { - (mockFieldsDefinitionRepository save _) expects FakeFieldsDefinition returns ((FakeFieldsDefinition, true)) - - val result = await(service.upsert(FakeContext, FakeVersion, FakeFieldsDefinitions)) - - result shouldBe ((FieldsDefinitionResponse(fakeRawContext, fakeRawVersion, FakeFieldsDefinitions), true)) - } - - "propagate the error" in { - (mockFieldsDefinitionRepository save(_: FieldsDefinition)) expects * returns Future.failed(emulatedFailure) - - val caught = intercept[EmulatedFailure] { - await(service.upsert(FakeContext, FakeVersion, FakeFieldsDefinitions)) - } - - caught shouldBe emulatedFailure - } - } - - "delete" should { - "return true when the record is removed from the database collection" in { - (mockFieldsDefinitionRepository delete (_:ApiContext, _:ApiVersion)).expects(FakeContext, FakeVersion) - .returns(true) - - await(service.delete(FakeContext, FakeVersion)) shouldBe true - } - - "return false when the record is not found in the database collection" in { - (mockFieldsDefinitionRepository delete (_:ApiContext, _:ApiVersion)).expects(FakeContext, FakeVersion) - .returns(false) - - await(service.delete(FakeContext, FakeVersion)) shouldBe false - } - } - -} diff --git a/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala b/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala index d536919..47f1e25 100644 --- a/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala +++ b/test/uk/gov/hmrc/apisubscriptionfields/service/SubscriptionFieldsServiceSpec.scala @@ -21,20 +21,20 @@ import java.util.UUID import org.scalamock.scalatest.MockFactory import uk.gov.hmrc.apisubscriptionfields.model._ import uk.gov.hmrc.apisubscriptionfields.repository._ -import uk.gov.hmrc.apisubscriptionfields.{FieldsDefinitionTestData, SubscriptionFieldsTestData} +import uk.gov.hmrc.apisubscriptionfields.{FieldDefinitionTestData, SubscriptionFieldsTestData} import uk.gov.hmrc.play.test.UnitSpec import cats.data.NonEmptyList import scala.concurrent.Future -class SubscriptionFieldsServiceSpec extends UnitSpec with SubscriptionFieldsTestData with FieldsDefinitionTestData with MockFactory { +class SubscriptionFieldsServiceSpec extends UnitSpec with SubscriptionFieldsTestData with FieldDefinitionTestData with MockFactory { private val mockSubscriptionFieldsIdRepository = mock[SubscriptionFieldsRepository] - private val mockFieldsDefinitionService = mock[FieldsDefinitionService] + private val mockApiFieldDefinitionsService = mock[ApiFieldDefinitionsService] private val mockUuidCreator = new UUIDCreator { override def uuid(): UUID = FakeRawFieldsId } - private val service = new SubscriptionFieldsService(mockSubscriptionFieldsIdRepository, mockUuidCreator, mockFieldsDefinitionService) + private val service = new SubscriptionFieldsService(mockSubscriptionFieldsIdRepository, mockUuidCreator, mockApiFieldDefinitionsService) "getAll" should { "return an empty list when no entry exists in the database collection" in { @@ -185,17 +185,17 @@ class SubscriptionFieldsServiceSpec extends UnitSpec with SubscriptionFieldsTest "validate" should { import eu.timepit.refined.auto._ "returns ValidSubsFieldValidationResponse when fields are Valid " in { - (mockFieldsDefinitionService get (_: ApiContext, _: ApiVersion)) + (mockApiFieldDefinitionsService get (_: ApiContext, _: ApiVersion)) .expects(FakeContext, FakeVersion) - .returns(Some(FakeFieldsDefinitionResponseWithRegex)) + .returns(Some(FakeApiFieldDefinitionsResponseWithRegex)) await(service.validate(FakeContext, FakeVersion, SubscriptionFieldsMatchRegexValidation)) shouldBe ValidSubsFieldValidationResponse } "returns InvalidSubsFieldValidationResponse when fields are Invalid " in { - (mockFieldsDefinitionService get (_: ApiContext, _: ApiVersion)) + (mockApiFieldDefinitionsService get (_: ApiContext, _: ApiVersion)) .expects(FakeContext, FakeVersion) - .returns(Some(FakeFieldsDefinitionResponseWithRegex)) + .returns(Some(FakeApiFieldDefinitionsResponseWithRegex)) await(service.validate(FakeContext, FakeVersion, SubscriptionFieldsDoNotMatchRegexValidation)) shouldBe FakeInvalidSubsFieldValidationResponse2 }