Skip to content

Commit

Permalink
PI-1858: Added throw-not-found property for disabling in dev (#3210)
Browse files Browse the repository at this point in the history
* PI-1858: Added throw-not-found property for disabling in dev
  • Loading branch information
pmcphee77 authored Feb 6, 2024
1 parent c570755 commit dab5b5c
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 7 deletions.
2 changes: 1 addition & 1 deletion projects/cas2-and-delius/deploy/values-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ generic-service:
env:
SENTRY_ENVIRONMENT: dev
SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_HMPPS-AUTH_TOKEN-URI: http://hmpps-auth.hmpps-auth-dev.svc.cluster.local/auth/oauth/token

EVENT_EXCEPTION_THROWNOTFOUND: false
LOGGING_LEVEL_UK_GOV_DIGITAL_JUSTICE_HMPPS: DEBUG

generic-prometheus-alerts:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"eventType": "applications.cas2.application.status-updated",
"version": 1,
"description": "A CAS2 application has been updated",
"detailUrl": "http://localhost:{wiremock.port}/approved-premises-api/events/cas2/application-status-updated/4444",
"occurredAt": "2020-01-01T12:34:56Z[Europe/London]",
"personReference": {
"identifiers": [
{
"type": "CRN",
"value": "A000001"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"eventType": "applications.cas2.application.submitted",
"version": 1,
"description": "A CAS2 application has been submitted",
"detailUrl": "http://localhost:{wiremock.port}/approved-premises-api/events/cas2/application-submitted/5555",
"occurredAt": "2020-01-01T12:34:56Z[Europe/London]",
"personReference": {
"identifiers": [
{
"type": "CRN",
"value": "A005555"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"eventType": "applications.cas2.application.submitted",
"version": 1,
"description": "A CAS2 application has been submitted",
"detailUrl": "http://localhost:{wiremock.port}/approved-premises-api/events/cas2/application-submitted/3333",
"occurredAt": "2020-01-01T12:34:56Z[Europe/London]",
"personReference": {
"identifiers": [
{
"type": "CRN",
"value": "A003333"
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@
"bodyFileName": "application-submitted.json"
}
},
{
"request": {
"method": "GET",
"urlPath": "/approved-premises-api/events/cas2/application-submitted/4444"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200,
"bodyFileName": "application-status-updated.json"
}
},
{
"request": {
"method": "GET",
Expand All @@ -25,6 +38,54 @@
"status": 200,
"bodyFileName": "application-status-updated.json"
}
},
{
"request": {
"method": "GET",
"urlPath": "/approved-premises-api/events/cas2/application-submitted/3333"
},
"response": {
"status": 404,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"status": 404,
"detail": "No DomainEvent with an ID of 3333 could be found"
}
}
},
{
"request": {
"method": "GET",
"urlPath": "/approved-premises-api/events/cas2/application-submitted/5555"
},
"response": {
"status": 400,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"status": 400,
"detail": "Bad Request"
}
}
},
{
"request": {
"method": "GET",
"urlPath": "/approved-premises-api/events/cas2/application-status-updated/4444"
},
"response": {
"status": 404,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"status": 404,
"detail": "No DomainEvent with an ID of 4444 could be found"
}
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import com.github.tomakehurst.wiremock.WireMockServer
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.verify
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.boot.test.system.CapturedOutput
import org.springframework.boot.test.system.OutputCaptureExtension
import uk.gov.justice.digital.hmpps.datetime.EuropeLondon
import uk.gov.justice.digital.hmpps.entity.ContactRepository
import uk.gov.justice.digital.hmpps.entity.ContactType.Companion.REFERRAL_SUBMITTED
Expand All @@ -20,6 +25,7 @@ import java.time.LocalDate
import java.time.ZonedDateTime

@SpringBootTest
@ExtendWith(OutputCaptureExtension::class)
internal class IntegrationTest {
@Value("\${messaging.consumer.queue}")
lateinit var queueName: String
Expand Down Expand Up @@ -120,4 +126,26 @@ internal class IntegrationTest {
mapOf()
)
}

@Test
fun `application submitted not found enabled`(output: CapturedOutput) {
// Given a message
val event = prepEvent("application-submitted-not-found", wireMockServer.port())
channelManager.getChannel(queueName).publishAndWait(event)
//Assert that expected exception exists in output
assertThat(output.all, containsString("No DomainEvent with an ID of 3333 could be found"))
//Assert that only 1 trackEvent for Notification Received has occurred
verify(telemetryService, Mockito.times(1)).trackEvent(any(), any(), any())
}

@Test
fun `application status not found enabled`(output: CapturedOutput) {
// Given a message
val event = prepEvent("application-status-updated-not-found", wireMockServer.port())
channelManager.getChannel(queueName).publishAndWait(event)
//Assert that expected exception exists in output
assertThat(output.all, containsString("No DomainEvent with an ID of 4444 could be found"))
//Assert that only 1 trackEvent for Notification Received has occurred
verify(telemetryService, Mockito.times(1)).trackEvent(any(), any(), any())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package uk.gov.justice.digital.hmpps

import com.github.tomakehurst.wiremock.WireMockServer
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.containsString
import org.hamcrest.Matchers.not
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.verify
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.boot.test.system.CapturedOutput
import org.springframework.boot.test.system.OutputCaptureExtension
import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService

@SpringBootTest(properties = ["event.exception.throw-not-found: false"])
@ExtendWith(OutputCaptureExtension::class)
internal class NotFoundIntegrationTest {
@Value("\${messaging.consumer.queue}")
lateinit var queueName: String

@Autowired
lateinit var channelManager: HmppsChannelManager

@Autowired
lateinit var wireMockServer: WireMockServer

@MockBean
lateinit var telemetryService: TelemetryService

@Test
fun `application submitted not found enabled`(output: CapturedOutput) {
// Given a message
val event = prepEvent("application-submitted-not-found", wireMockServer.port())
channelManager.getChannel(queueName).publishAndWait(event)
//Assert that expected exception exists in output
assertThat(output.all, not(containsString("No DomainEvent with an ID of 3333 could be found")))
//Assert that only 1 trackEvent for Notification Received has occurred
verify(telemetryService, Mockito.times(1)).trackEvent(any(), any(), any())
}

@Test
fun `application status not found enabled`(output: CapturedOutput) {
// Given a message
val event = prepEvent("application-status-updated-not-found", wireMockServer.port())
channelManager.getChannel(queueName).publishAndWait(event)
//Assert that expected exception exists in output
assertThat(output.all, not(containsString("No DomainEvent with an ID of 4444 could be found")))
//Assert that only 1 trackEvent for Notification Received has occurred
verify(telemetryService, Mockito.times(1)).trackEvent(any(), any(), any())
}

@Test
fun `application submitted bad request still thrown`(output: CapturedOutput) {
// Given a message
val event = prepEvent("application-submitted-bad-request", wireMockServer.port())
channelManager.getChannel(queueName).publishAndWait(event)
//Assert that expected exception exists in output
assertThat(output.all, containsString("Bad Request"))
//Assert that only 1 trackEvent for Notification Received has occurred
verify(telemetryService, Mockito.times(1)).trackEvent(any(), any(), any())
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package uk.gov.justice.digital.hmpps.messaging

import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.client.HttpStatusCodeException
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.message.Notification
Expand All @@ -10,18 +13,25 @@ import uk.gov.justice.digital.hmpps.telemetry.notificationReceived

@Component
class Handler(
@Value("\${event.exception.throw-not-found:true}") private val throwNotFound: Boolean,
override val converter: NotificationConverter<HmppsDomainEvent>,
private val telemetryService: TelemetryService,
private val cas2Service: Cas2Service,
) : NotificationHandler<HmppsDomainEvent> {
override fun handle(notification: Notification<HmppsDomainEvent>) {
telemetryService.notificationReceived(notification)
val event = notification.message
when (event.eventType) {
"applications.cas2.application.submitted" -> cas2Service.applicationSubmitted(event)
"applications.cas2.application.status-updated" -> cas2Service.applicationStatusUpdated(event)
try {
when (event.eventType) {
"applications.cas2.application.submitted" -> cas2Service.applicationSubmitted(event)
"applications.cas2.application.status-updated" -> cas2Service.applicationStatusUpdated(event)

else -> throw IllegalArgumentException("Unexpected event type ('${event.eventType}')")
else -> throw IllegalArgumentException("Unexpected event type ('${event.eventType}')")
}
} catch (ex: HttpStatusCodeException) {
if (ex.statusCode != HttpStatus.NOT_FOUND || throwNotFound) {
throw ex
}
}
}
}
2 changes: 2 additions & 0 deletions projects/cas2-and-delius/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ context.initializer.classes: uk.gov.justice.digital.hmpps.wiremock.WireMockIniti

messaging.consumer.queue: message-queue

event.exception.throw-not-found: true

integrations:
example:
url: http://localhost:${wiremock.port}/example
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package uk.gov.justice.digital.hmpps.messaging

import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.containsString
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.whenever
import org.springframework.http.HttpStatus
import org.springframework.web.client.HttpClientErrorException
import uk.gov.justice.digital.hmpps.converter.NotificationConverter
import uk.gov.justice.digital.hmpps.message.HmppsDomainEvent
import uk.gov.justice.digital.hmpps.message.MessageAttributes
import uk.gov.justice.digital.hmpps.message.Notification
import uk.gov.justice.digital.hmpps.prepEvent
import uk.gov.justice.digital.hmpps.service.Cas2Service
import uk.gov.justice.digital.hmpps.telemetry.TelemetryService

@ExtendWith(MockitoExtension::class)
internal class HandlerTest {

@Mock
lateinit var converter: NotificationConverter<HmppsDomainEvent>

Expand All @@ -26,15 +32,60 @@ internal class HandlerTest {
@Mock
lateinit var cas2Service: Cas2Service

@InjectMocks
lateinit var handler: Handler

@Test
fun `handles unexpected event type`() {
handler = Handler(true, converter, telemetryService, cas2Service)
val exception = assertThrows<IllegalArgumentException> {
handler.handle(Notification(HmppsDomainEvent("unknown", 1), MessageAttributes("unknown")))
}

assertThat(exception.message, equalTo("Unexpected event type ('unknown')"))
}

@Test
fun `throws NotFoundException`() {
handler = Handler(true, converter, telemetryService, cas2Service)
val event = prepEvent("application-submitted")
whenever(cas2Service.applicationSubmitted(event.message)).thenThrow(
HttpClientErrorException(
HttpStatus.NOT_FOUND,
"DomainEvent not found"
)
)
val exception = assertThrows<HttpClientErrorException> {
handler.handle(Notification(event.message, event.attributes, event.id))
}
assertThat(exception.message, containsString("DomainEvent not found"))
}

@Test
fun `does not throw NotFoundException`() {
handler = Handler(false, converter, telemetryService, cas2Service)
val event = prepEvent("application-submitted")
whenever(cas2Service.applicationSubmitted(event.message)).thenThrow(
HttpClientErrorException(
HttpStatus.NOT_FOUND,
"DomainEvent not found"
)
)
assertDoesNotThrow { handler.handle(Notification(event.message, event.attributes, event.id)) }
}

@Test
fun `still throws Bad Request exception`() {
handler = Handler(false, converter, telemetryService, cas2Service)
val event = prepEvent("application-submitted")
whenever(cas2Service.applicationSubmitted(event.message)).thenThrow(
HttpClientErrorException(
HttpStatus.BAD_REQUEST,
"Bad Request"
)
)
val exception = assertThrows<HttpClientErrorException> {
handler.handle(Notification(event.message, event.attributes, event.id))
}
assertThat(exception.message, containsString("Bad Request"))
}
}

0 comments on commit dab5b5c

Please sign in to comment.