diff --git a/README.md b/README.md index ab28696..4a8eea8 100644 --- a/README.md +++ b/README.md @@ -19,46 +19,70 @@ then publish its definition to the API Definition service and its scope to the A ### POST /publish Jenkins uses this endpoint to notify of a new microservice ### Request Payload Example -``` +```json { - "serviceName":"hello-world", - "serviceUrl":"http://hello-world.example.com", - "metadata":{ - "key1": "value1", - "key2": "value2" - } + "serviceName": "hello-world", + "serviceUrl": "http://hello-world.example.com", + "metadata": { + "key1": "value1", + "key2": "value2" + } } ``` ### Responses +#### 200 OK +The request was successful and the API Definition and Scopes have been published +##### Response Payload Example +```json +{ + "name": "Hello World", + "serviceName": "hello-world", + "context": "test/hello", + "description": "A 'hello world' example API", + "versions": [ + { + "version": "1.0", + "status": "STABLE", + "endpointsEnabled": true + }, + { + "version": "2.0", + "status": "ALPHA", + "endpointsEnabled": false + } + ] +} +``` +Possible statuses: ALPHA, BETA, STABLE, DEPRECATED, RETIRED + #### 202 Accepted -No response as the request was successful and the API has been published and is awaiting approval -#### 204 No Content -No response as the request was successful and the API Definition and Scopes have been published +No response as the request was successful but the API is awaiting approval in Gatekeeper and has not been published + #### 400 Bad Request The response will contain information regarding why the request could not be understood -``` +```json { "statusCode": 400, "message": "Invalid Json: No content to map due to end-of-input\n at [Source: (akka.util.ByteIterator$ByteArrayIterator$$anon$1); line: 1, column: 0]" } ``` #### 401 Unauthorized -``` +```json { "code": "UNAUTHORIZED", "message": "Agent must be authorised to perform Publish or Validate actions" } ``` #### 415 Unsupported Media Type -``` +```json { "statusCode": 415, "message": "Expecting text/json or application/json body" } ``` #### 422 Unprocessable Entity - Invalid Request Payload -``` +```json { "code": "API_PUBLISHER_INVALID_REQUEST_PAYLOAD", "message": { @@ -74,7 +98,7 @@ The response will contain information regarding why the request could not be und } ``` #### 500 Internal Server Error -``` +```json { "code": "API_PUBLISHER_UNKNOWN_ERROR", "message": "An unexpected error occurred: GET of 'http://localhost/api/definition' failed. Caused by: 'Connection refused: localhost/127.0.0.1:80'" @@ -83,7 +107,7 @@ The response will contain information regarding why the request could not be und ### POST /validate ### Request Payload Example -``` +```json { "api": { "name":"Exmaple API", @@ -127,7 +151,7 @@ The response will contain information regarding why the request could not be und #### 204 No Content No response as the request was successful #### 400 Bad Request - Missing Payload -``` +```json { "statusCode": 400, "message": "Invalid Json: No content to map due to end-of-input\n at [Source: (akka.util.ByteIterator$ByteArrayIterator$$anon$1); line: 1, column: 0]" @@ -135,28 +159,28 @@ No response as the request was successful ``` #### 400 Bad Request - Scope Changed Error This response is related to the inability to change scopes when publishing. -``` +```json { "scopeChangedErrors": "Updating scopes while publishing is no longer supported. See https://confluence.tools.tax.service.gov.uk/display/TEC/2021/09/07/Changes+to+scopes for more information" } ``` #### 400 Bad Request - API Publisher Unknown Error The message in this response could contain any number of errors related to problems in the request payload. An example is shown below. -``` +```json { "code": "API_PUBLISHER_UNKNOWN_ERROR", "message": "An unexpected error occurred: POST of 'http://localhost:9604/api-definition/validate' returned 422. Response body: '{\"code\":\"INVALID_REQUEST_PAYLOAD\",\"messages\":[\"Field 'categories' should exist and not be empty for API 'Exmaple API'\"]}'" } ``` #### 401 Unauthorized -``` +```json { "code": "UNAUTHORIZED", "message": "Agent must be authorised to perform Publish or Validate actions" } ``` #### 415 Unsupported Media Type -``` +```json { "statusCode": 415, "message": "Expecting text/json or application/json body" diff --git a/app/uk/gov/hmrc/apipublisher/connectors/MicroserviceConnector.scala b/app/uk/gov/hmrc/apipublisher/connectors/MicroserviceConnector.scala index 328e422..9c00c06 100644 --- a/app/uk/gov/hmrc/apipublisher/connectors/MicroserviceConnector.scala +++ b/app/uk/gov/hmrc/apipublisher/connectors/MicroserviceConnector.scala @@ -19,9 +19,9 @@ package uk.gov.hmrc.apipublisher.connectors import java.io.{FileNotFoundException, InputStream} import java.nio.charset.StandardCharsets.UTF_8 import javax.inject.{Inject, Singleton} -import scala.jdk.CollectionConverters._ import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ExecutionContext, Future, blocking} +import scala.jdk.CollectionConverters._ import scala.util.Try import akka.actor.ActorSystem diff --git a/app/uk/gov/hmrc/apipublisher/controllers/PublisherController.scala b/app/uk/gov/hmrc/apipublisher/controllers/PublisherController.scala index 10cafe9..991f7c2 100644 --- a/app/uk/gov/hmrc/apipublisher/controllers/PublisherController.scala +++ b/app/uk/gov/hmrc/apipublisher/controllers/PublisherController.scala @@ -31,7 +31,7 @@ import uk.gov.hmrc.http.{HeaderCarrier, UnprocessableEntityException} import uk.gov.hmrc.play.bootstrap.backend.controller.BackendController import uk.gov.hmrc.apipublisher.exceptions.UnknownApiServiceException -import uk.gov.hmrc.apipublisher.models.{ApiAndScopes, ErrorCode, ServiceLocation} +import uk.gov.hmrc.apipublisher.models.{ApiAndScopes, ErrorCode, PublicationResult, ServiceLocation} import uk.gov.hmrc.apipublisher.services.{ApprovalService, DefinitionService, PublisherService} import uk.gov.hmrc.apipublisher.util.ApplicationLogger import uk.gov.hmrc.apipublisher.wiring.AppContext @@ -78,10 +78,10 @@ class PublisherController @Inject() ( def publish(apiAndScopes: ApiAndScopes): Future[Result] = { publisherService.publishAPIDefinitionAndScopes(serviceLocation, apiAndScopes).map { - case true => + case PublicationResult(true, publisherResponse) => logger.info(s"Successfully published API Definition and Scopes for ${serviceLocation.serviceName}") - NoContent - case false => + Ok(Json.toJson(publisherResponse)) + case PublicationResult(false, _) => logger.info(s"Publication awaiting approval for ${serviceLocation.serviceName}") Accepted } @@ -116,12 +116,15 @@ class PublisherController @Inject() ( } def approve(serviceName: String): Action[AnyContent] = Action.async { implicit request => - ({ + { for { serviceLocation <- approvalService.approveService(serviceName) - result <- publishService(serviceLocation) + result <- publishService(serviceLocation).map { + case Result(ResponseHeader(OK, _, _), _, _, _, _) => NoContent + case other => other + } } yield result - }) recover recovery(FAILED_TO_APPROVE_SERVICES) + } recover recovery(FAILED_TO_APPROVE_SERVICES) } private def handleRequest[T](prefix: String)(f: T => Future[Result])(implicit request: Request[JsValue], reads: Reads[T]): Future[Result] = { diff --git a/app/uk/gov/hmrc/apipublisher/models/PublisherResponse.scala b/app/uk/gov/hmrc/apipublisher/models/PublisherResponse.scala new file mode 100644 index 0000000..ac0ee1e --- /dev/null +++ b/app/uk/gov/hmrc/apipublisher/models/PublisherResponse.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.apipublisher.models + +import play.api.libs.json._ + +case class PublicationResult(approved: Boolean, publisherResponse: Option[PublisherResponse]) + +case class PublisherResponse(name: String, serviceName: String, context: String, description: String, versions: List[PartialApiVersion]) + +object PublisherResponse { + implicit val format: OFormat[PublisherResponse] = Json.format[PublisherResponse] +} + +case class PartialApiVersion(version: String, status: ApiStatus, endpointsEnabled: Option[Boolean]) + +object PartialApiVersion { + implicit val format: OFormat[PartialApiVersion] = Json.format[PartialApiVersion] +} + +sealed trait ApiStatus + +object ApiStatus { + case object ALPHA extends ApiStatus + case object BETA extends ApiStatus + case object STABLE extends ApiStatus + case object DEPRECATED extends ApiStatus + case object RETIRED extends ApiStatus + + def apply(text: String): Option[ApiStatus] = text.toUpperCase() match { + case "ALPHA" => Some(ALPHA) + case "BETA" => Some(BETA) + case "STABLE" => Some(STABLE) + case "DEPRECATED" => Some(DEPRECATED) + case "RETIRED" => Some(RETIRED) + case _ => None + } + + private val convert: String => JsResult[ApiStatus] = s => ApiStatus(s).fold[JsResult[ApiStatus]](JsError(s"$s is not a status"))(status => JsSuccess(status)) + + implicit val reads: Reads[ApiStatus] = JsPath.read[String].flatMapResult(convert(_)) + + implicit val writes: Writes[ApiStatus] = Writes[ApiStatus](status => JsString(status.toString)) + + implicit val format: Format[ApiStatus] = Format(reads, writes) +} diff --git a/app/uk/gov/hmrc/apipublisher/models/oas/SOpenAPI.scala b/app/uk/gov/hmrc/apipublisher/models/oas/SOpenAPI.scala index c8a354c..e505f52 100644 --- a/app/uk/gov/hmrc/apipublisher/models/oas/SOpenAPI.scala +++ b/app/uk/gov/hmrc/apipublisher/models/oas/SOpenAPI.scala @@ -17,9 +17,9 @@ package uk.gov.hmrc.apipublisher.models.oas import java.util.function.BiConsumer -import scala.jdk.CollectionConverters._ import scala.collection.immutable.ListMap import scala.collection.mutable.Buffer +import scala.jdk.CollectionConverters._ import io.swagger.models.Method import io.swagger.v3.oas.models._ diff --git a/app/uk/gov/hmrc/apipublisher/services/PublisherService.scala b/app/uk/gov/hmrc/apipublisher/services/PublisherService.scala index 81a66c9..3346ffa 100644 --- a/app/uk/gov/hmrc/apipublisher/services/PublisherService.scala +++ b/app/uk/gov/hmrc/apipublisher/services/PublisherService.scala @@ -36,7 +36,7 @@ class PublisherService @Inject() ( )(implicit val ec: ExecutionContext ) extends ApplicationLogger { - def publishAPIDefinitionAndScopes(serviceLocation: ServiceLocation, apiAndScopes: ApiAndScopes)(implicit hc: HeaderCarrier): Future[Boolean] = { + def publishAPIDefinitionAndScopes(serviceLocation: ServiceLocation, apiAndScopes: ApiAndScopes)(implicit hc: HeaderCarrier): Future[PublicationResult] = { def apiDetailsWithServiceLocation(apiAndScopes: ApiAndScopes): JsObject = { apiAndScopes.apiWithoutFieldDefinitions ++ Json.obj( @@ -45,12 +45,13 @@ class PublisherService @Inject() ( ) } - def publish(apiAndScopes: ApiAndScopes): Future[Boolean] = { + def publish(apiAndScopes: ApiAndScopes): Future[PublicationResult] = { for { - _ <- apiScopeConnector.publishScopes(apiAndScopes.scopes) - _ <- apiDefinitionConnector.publishAPI(apiDetailsWithServiceLocation(apiAndScopes)) - _ <- publishFieldDefinitions(apiAndScopes.fieldDefinitions) - } yield true + _ <- apiScopeConnector.publishScopes(apiAndScopes.scopes) + api = apiDetailsWithServiceLocation(apiAndScopes) + _ <- apiDefinitionConnector.publishAPI(api) + _ <- publishFieldDefinitions(apiAndScopes.fieldDefinitions) + } yield PublicationResult(approved = true, Some(api.as[PublisherResponse])) } def publishFieldDefinitions(fieldDefinitions: Seq[ApiFieldDefinitions]): Future[Unit] = { @@ -61,10 +62,10 @@ class PublisherService @Inject() ( } } - def checkApprovedAndPublish(apiAndScopes: ApiAndScopes): Future[Boolean] = { + def checkApprovedAndPublish(apiAndScopes: ApiAndScopes): Future[PublicationResult] = { for { isApproved <- checkApproval(serviceLocation, apiAndScopes.apiName, apiAndScopes.description) - result <- if (isApproved) publish(apiAndScopes) else successful(false) + result <- if (isApproved) publish(apiAndScopes) else successful(PublicationResult(approved = false, None)) } yield result } diff --git a/it/uk/gov/hmrc/apipublisher/PublisherFeatureSpec.scala b/it/uk/gov/hmrc/apipublisher/PublisherFeatureSpec.scala index 86b3654..8701eef 100644 --- a/it/uk/gov/hmrc/apipublisher/PublisherFeatureSpec.scala +++ b/it/uk/gov/hmrc/apipublisher/PublisherFeatureSpec.scala @@ -160,7 +160,7 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | "versions": [ | { | "version": "1.0", - | "status": "PUBLISHED" + | "status": "STABLE" | } | ] | } @@ -184,7 +184,7 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | "versions": [ | { | "version": "1.0", - | "status": "PUBLISHED", + | "status": "STABLE", | "fieldDefinitions": [ | { | "name": "callbackUrl", @@ -202,11 +202,11 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | }, | { | "version": "2.0", - | "status": "PUBLISHED" + | "status": "STABLE" | }, | { | "version": "3.0", - | "status": "PUBLISHED", + | "status": "STABLE", | "fieldDefinitions": [ | { | "name": "callbackUrlOnly", @@ -266,7 +266,7 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | "versions" : [ | { | "version" : "1.0", - | "status" : "PUBLISHED", + | "status" : "STABLE", | "endpoints": [ | { | "uriPattern": "/hello", @@ -279,7 +279,7 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | }, | { | "version" : "2.0", - | "status" : "PUBLISHED", + | "status" : "STABLE", | "endpoints": [ | { | "uriPattern": "/hello", @@ -293,7 +293,7 @@ class PublisherFeatureSpec extends BaseFeatureSpec { | }, | { | "version" : "3.0", - | "status" : "PUBLISHED", + | "status" : "STABLE", | "endpoints": [ | { | "uriPattern": "/hello", diff --git a/run_local_with_dependencies.sh b/run_local_with_dependencies.sh index ae5a6fe..7edf849 100755 --- a/run_local_with_dependencies.sh +++ b/run_local_with_dependencies.sh @@ -1,5 +1,5 @@ #!/bin/bash -sm --start API_DEFINITION API_SCOPE API_SUBSCRIPTION_FIELDS API_EXAMPLE_MICROSERVICE API_DOCUMENTATION_FRONTEND +sm2 --start API_DEFINITION API_SCOPE API_SUBSCRIPTION_FIELDS API_EXAMPLE_MICROSERVICE API_DOCUMENTATION_FRONTEND ./run_local.sh diff --git a/test/resources/input/api-with-endpoints-and-fields.json b/test/resources/input/api-with-endpoints-and-fields.json index fc16eb4..91ba9bf 100644 --- a/test/resources/input/api-with-endpoints-and-fields.json +++ b/test/resources/input/api-with-endpoints-and-fields.json @@ -9,7 +9,7 @@ "type" : "PRIVATE", "whitelistApplicationIds" : ["76327c12-17fa-4a51-8a8b-23f7251fae1b","76327c12-17fa-4a51-8a8b-23f7251fae1a"] }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPattern" : "/hello", @@ -64,7 +64,7 @@ "access" : { "type" : "PUBLIC" }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPattern" : "/hello", @@ -89,7 +89,7 @@ "access": { "type" : "PUBLIC" }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPatter" : "/hello", @@ -117,7 +117,7 @@ }, { "version" : "3.0", - "status" : "PROTOTYPED", + "status" : "BETA", "endpoints" : [ { "uriPattern" : "/hello", diff --git a/test/resources/input/api-with-endpoints.json b/test/resources/input/api-with-endpoints.json index f655fc8..5e9c43c 100644 --- a/test/resources/input/api-with-endpoints.json +++ b/test/resources/input/api-with-endpoints.json @@ -9,7 +9,7 @@ "type" : "PRIVATE", "whitelistApplicationIds" : ["76327c12-17fa-4a51-8a8b-23f7251fae1b","76327c12-17fa-4a51-8a8b-23f7251fae1a"] }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPattern" : "/hello", @@ -25,7 +25,7 @@ "access" : { "type" : "PUBLIC" }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPattern" : "/hello", @@ -42,7 +42,7 @@ "access": { "type" : "PUBLIC" }, - "status" : "PUBLISHED", + "status" : "STABLE", "endpoints" : [ { "uriPatter" : "/hello", @@ -56,7 +56,7 @@ }, { "version" : "3.0", - "status" : "PROTOTYPED", + "status" : "BETA", "endpoints" : [ { "uriPattern" : "/hello", diff --git a/test/uk/gov/hmrc/apipublisher/controllers/PublisherControllerSpec.scala b/test/uk/gov/hmrc/apipublisher/controllers/PublisherControllerSpec.scala index e060437..41d3897 100644 --- a/test/uk/gov/hmrc/apipublisher/controllers/PublisherControllerSpec.scala +++ b/test/uk/gov/hmrc/apipublisher/controllers/PublisherControllerSpec.scala @@ -35,7 +35,8 @@ import uk.gov.hmrc.http.HeaderNames.xRequestId import uk.gov.hmrc.http.{HeaderCarrier, UnprocessableEntityException} import uk.gov.hmrc.apipublisher.exceptions.UnknownApiServiceException -import uk.gov.hmrc.apipublisher.models.{APIApproval, ApiAndScopes, ServiceLocation} +import uk.gov.hmrc.apipublisher.models.ApiStatus._ +import uk.gov.hmrc.apipublisher.models._ import uk.gov.hmrc.apipublisher.services._ import uk.gov.hmrc.apipublisher.wiring.AppContext @@ -57,6 +58,18 @@ class PublisherControllerSpec extends AsyncHmrcSpec with GuiceOneAppPerSuite wit private val marriageAllowanceApproval = APIApproval("marriage-allowance", "http://marriage.example.com", "Marriage Allowance", Some("Check Marriage Allowance"), Some(false)) + private val publisherResponse = PublisherResponse( + name = "Example API", + serviceName = "example-api", + context = "test/example", + description = "An example of an API", + versions = List(PartialApiVersion( + version = "1.0", + status = STABLE, + endpointsEnabled = Some(true) + )) + ) + trait BaseSetup { implicit val hc = HeaderCarrier().withExtraHeaders(xRequestId -> "requestId") val mockPublisherService = mock[PublisherService] @@ -70,7 +83,10 @@ class PublisherControllerSpec extends AsyncHmrcSpec with GuiceOneAppPerSuite wit trait Setup extends BaseSetup { when(mockDefinitionService.getDefinition(*)(*)).thenReturn(successful(Some(apiAndScopes))) when(mockPublisherService.validation(eqTo(apiAndScopes), eqTo(false))(*)).thenReturn(successful(None)) - when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*)).thenReturn(successful(true)) + when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*)).thenReturn(successful(PublicationResult( + approved = true, + Some(publisherResponse) + ))) when(mockAppContext.publishingKey).thenReturn(sharedSecret) } @@ -95,17 +111,18 @@ class PublisherControllerSpec extends AsyncHmrcSpec with GuiceOneAppPerSuite wit contentAsString(result).contains("Bang") shouldBe true } - "respond with 204 (NO_CONTENT) when service APIs successfully published" in new Setup { + "respond with 200 (OK) when service APIs successfully published" in new Setup { val validRequest = request(serviceLocation, sharedSecret) val result = underTest.publish(validRequest) - status(result) shouldEqual NO_CONTENT + status(result) shouldEqual OK + contentAsJson(result) shouldBe Json.toJson(publisherResponse) verify(mockPublisherService).publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*) } "respond with 202 (ACCEPTED) when service APIs not published because it awaits an approval" in new Setup { - when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*)).thenReturn(successful(false)) + when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*)).thenReturn(successful(PublicationResult(approved = false, None))) val validRequest = request(serviceLocation, sharedSecret) @@ -253,14 +270,16 @@ class PublisherControllerSpec extends AsyncHmrcSpec with GuiceOneAppPerSuite wit "approve a known service" in new Setup { - private val testServiceLocation = ServiceLocation("employee-paye", "http://localhost/employee-paye") - when(mockApprovalService.approveService("employee-paye")).thenReturn(successful(testServiceLocation)) - when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(testServiceLocation), *)(*)).thenReturn(successful(true)) + when(mockApprovalService.approveService("employee-paye")).thenReturn(successful(serviceLocation)) + when(mockPublisherService.publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*)).thenReturn(successful(PublicationResult( + approved = true, + Some(publisherResponse) + ))) val result = underTest.approve("employee-paye")(FakeRequest()) status(result) shouldBe NO_CONTENT - verify(mockPublisherService).publishAPIDefinitionAndScopes(eqTo(testServiceLocation), *)(*) + verify(mockPublisherService).publishAPIDefinitionAndScopes(eqTo(serviceLocation), *)(*) } "raise an error when attempting to approve an unknown service" in new Setup { diff --git a/test/uk/gov/hmrc/apipublisher/services/OasParserImplSpec.scala b/test/uk/gov/hmrc/apipublisher/services/OasParserImplSpec.scala index 41c8a2a..c4614a1 100644 --- a/test/uk/gov/hmrc/apipublisher/services/OasParserImplSpec.scala +++ b/test/uk/gov/hmrc/apipublisher/services/OasParserImplSpec.scala @@ -21,12 +21,12 @@ import scala.jdk.CollectionConverters._ import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.parser.OpenAPIV3Parser import io.swagger.v3.parser.core.models.ParseOptions +import org.scalatest.Inside import utils.HmrcSpec import uk.gov.hmrc.ramltools.domain.QueryParam import uk.gov.hmrc.apipublisher.util.ApplicationLogger -import org.scalatest.Inside class OasParserImplSpec extends HmrcSpec with ApplicationLogger { @@ -94,7 +94,7 @@ class OasParserImplSpec extends HmrcSpec with ApplicationLogger { |""".stripMargin) inside(parser.apply(None)(sample)) { - case (result :: Nil) => + case (result :: Nil) => result.uriPattern shouldBe "/hello/world" result.method shouldBe "GET" result.endpointName shouldBe "no endpoint name provided" diff --git a/test/uk/gov/hmrc/apipublisher/services/PublisherServiceSpec.scala b/test/uk/gov/hmrc/apipublisher/services/PublisherServiceSpec.scala index 600efbc..f76f04c 100644 --- a/test/uk/gov/hmrc/apipublisher/services/PublisherServiceSpec.scala +++ b/test/uk/gov/hmrc/apipublisher/services/PublisherServiceSpec.scala @@ -27,6 +27,7 @@ import uk.gov.hmrc.http.HeaderNames.xRequestId import uk.gov.hmrc.apipublisher.connectors.{APIDefinitionConnector, APIScopeConnector, APISubscriptionFieldsConnector} import uk.gov.hmrc.apipublisher.models +import uk.gov.hmrc.apipublisher.models.ApiStatus._ import uk.gov.hmrc.apipublisher.models._ class PublisherServiceSpec extends AsyncHmrcSpec { @@ -56,6 +57,19 @@ class PublisherServiceSpec extends AsyncHmrcSpec { val emulatedServiceError = new UnsupportedOperationException("Emulating a failure") + val publisherResponse = PublisherResponse( + name = "Test", + serviceName = "test", + context = "test", + description = "Test API", + versions = List( + PartialApiVersion(version = "1.0", status = STABLE, endpointsEnabled = None), + PartialApiVersion(version = "2.0", status = STABLE, endpointsEnabled = None), + PartialApiVersion(version = "2.1", status = STABLE, endpointsEnabled = None), + PartialApiVersion(version = "3.0", status = BETA, endpointsEnabled = None) + ) + ) + trait Setup { implicit val hc: HeaderCarrier = HeaderCarrier().withExtraHeaders(xRequestId -> "requestId") val mockApiDefinitionConnector: APIDefinitionConnector = mock[APIDefinitionConnector] @@ -80,7 +94,7 @@ class PublisherServiceSpec extends AsyncHmrcSpec { "Retrieve the api from the microservice and Publish it to api-definition, api-subscription-fields, api-scope and api-documentation if publication is allowed" in new Setup { - await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopes)) shouldBe true + await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopes)) shouldBe PublicationResult(approved = true, Some(publisherResponse)) verify(mockApiDefinitionConnector).publishAPI(*)(*) verify(mockApiScopeConnector).publishScopes(eqTo(scopes))(*) @@ -91,7 +105,7 @@ class PublisherServiceSpec extends AsyncHmrcSpec { when(mockApprovalService.createOrUpdateServiceApproval(*)).thenReturn(successful(false)) - await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopes)) shouldBe false + await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopes)) shouldBe PublicationResult(approved = false, None) verifyZeroInteractions(mockApiDefinitionConnector) verifyZeroInteractions(mockApiScopeConnector) @@ -99,7 +113,7 @@ class PublisherServiceSpec extends AsyncHmrcSpec { } "When publication allowed and api does not have subscription fields, publish API to api-definition, api-scope and api-documentation only" in new Setup { - await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopesWithoutFieldDefinitions)) shouldBe true + await(publisherService.publishAPIDefinitionAndScopes(testServiceLocation, apiAndScopesWithoutFieldDefinitions)) shouldBe PublicationResult(approved = true, Some(publisherResponse)) verify(mockApiScopeConnector).publishScopes(eqTo(scopes))(*) verifyZeroInteractions(mockApiSubscriptionFieldsConnector)