Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-1858: Added throw-not-found property for disabling in dev #3210

Merged
merged 5 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"))
}
}
Loading