Skip to content

Commit

Permalink
wiremock implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
karlfosterBCL committed Mar 7, 2025
1 parent 1c8f95e commit 9601424
Show file tree
Hide file tree
Showing 23 changed files with 555 additions and 195 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,21 @@ jobs:
build/reports/tests
services:
localstack:
image: localstack/localstack:3
image: localstack/localstack:4
env:
SERVICES: sqs,sns
DEFAULT_REGION: eu-west-2
ports:
- 4566:4566
wiremock-integration:
image: wiremock/wiremock:latest
volumes:
- ./wiremock/extensions:/var/wiremock/extensions
- ./wiremock/__files:/home/wiremock/__files
- ./wiremock/mappings:/home/wiremock/mappings
#entrypoint: [ "/docker-entrypoint.sh", "--disable-gzip", "--verbose" ]
ports:
- "9101:8080"
postgres:
image: postgres:17
env:
Expand Down
3 changes: 1 addition & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.flywaydb:flyway-core")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.apache.pdfbox:pdfbox:2.0.29")
implementation("org.apache.pdfbox:pdfbox:2.0.33")
implementation("uk.gov.justice.service.hmpps:hmpps-sqs-spring-boot-starter:5.3.2")
runtimeOnly("org.flywaydb:flyway-database-postgresql")
runtimeOnly("org.postgresql:postgresql")
Expand All @@ -26,7 +26,6 @@ dependencies {
testImplementation("io.swagger.parser.v3:swagger-parser:2.1.25") {
exclude(group = "io.swagger.core.v3")
}
testImplementation("org.testcontainers:localstack:1.20.5")
}

kotlin {
Expand Down
18 changes: 0 additions & 18 deletions docker-compose-wiremock.yml

This file was deleted.

14 changes: 13 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ services:
networks:
- hmpps
localstack:
image: localstack/localstack:3
image: localstack/localstack:4
networks:
- hmpps
container_name: localstack-external
Expand All @@ -39,6 +39,18 @@ services:
- DEFAULT_REGION=eu-west-2
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
wiremock-integration:
image: wiremock/wiremock:latest
container_name: wiremock-integration
volumes:
- ./wiremock/extensions:/var/wiremock/extensions
- ./wiremock/__files:/home/wiremock/__files
- ./wiremock/mappings:/home/wiremock/mappings
entrypoint: [ "/docker-entrypoint.sh", "--disable-gzip", "--verbose" ]
ports:
- "9101:8080"
networks:
- hmpps

networks:
hmpps:
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class DomainEventsListener(
// Update CRNs where appropriate
val breachNotices = breachNoticeService.getActiveBreachNoticesForCrn(message.sourceCrn)
breachNotices.forEach {
message.targetCrn?.let { it1 -> breachNoticeService.updateBreachNoticeCrn(it, it1) }
breachNoticeService.updateBreachNoticeCrn(it, requireNotNull(message.targetCrn))
}

updateReviewEvent(ReviewEventType.MERGE, breachNotices, message.occurredAt)
Expand All @@ -44,10 +44,10 @@ class DomainEventsListener(
// Update CRNs where appropriate
val breachNotices = breachNoticeService.getActiveBreachNoticesForCrn(message.unmergedCrn)
breachNotices.forEach {
nDeliusIntegrationService.getCrnForBreachNoticeUuid(it.id.toString())?.crn?.let { it1 ->
nDeliusIntegrationService.getCrnForBreachNoticeUuid(it.id.toString())?.crn?.let { crn ->
breachNoticeService.updateBreachNoticeCrn(
it,
it1,
crn,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package uk.gov.justice.digital.hmpps.breachnoticeapi.service
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException
import reactor.core.publisher.Mono

@Service
class NDeliusIntegrationService(
Expand All @@ -13,6 +15,7 @@ class NDeliusIntegrationService(
.uri(ndeliusIntegrationApiUrl + "/case/{breachNoticeId}", breachNoticeId)
.retrieve()
.bodyToMono(NDeliusCrn::class.java)
.onErrorResume(WebClientResponseException.NotFound::class.java) { Mono.empty() }
.block()
}

Expand Down
13 changes: 0 additions & 13 deletions src/main/resources/application-localstack.yml

This file was deleted.

9 changes: 7 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,17 @@ ndelius-integration-api.url: http://localhost:9101

---
spring.config.activate.on-profile: test
hmpps-auth.url: http://localhost:9090/auth
hmpps-auth.url: http://localhost:9101/auth
#hmpps-auth.url: http://localhost:9090/auth
frontend.url: http://localhost:3000
gotenberg.url: http://localhost:8072
#gotenberg.url: http://localhost:8072
gotenberg.url: http://localhost:9101
ndelius-integration-api.url: http://localhost:9101
spring.datasource:
url: jdbc:tc:postgresql:17:///breachdb

---
spring.config.activate.on-profile: [test, dev]
hmpps.sqs:
provider: localstack
queues:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import software.amazon.awssdk.services.sns.model.PublishRequest
import uk.gov.justice.digital.hmpps.breachnoticeapi.entity.BreachNoticeEntity
import uk.gov.justice.digital.hmpps.breachnoticeapi.model.BreachNotice
import uk.gov.justice.digital.hmpps.breachnoticeapi.repository.BreachNoticeRepository
import java.time.LocalDateTime
import java.util.concurrent.TimeUnit

class DomainEventTest : IntegrationTestBase() {
Expand Down Expand Up @@ -56,5 +57,148 @@ class DomainEventTest : IntegrationTestBase() {
assertThat(breachNoticeUpdated.reviewEvent).isEqualTo("MERGE")
}
}

@Test
fun `merge event should not update CRN for completed breach notice`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_BREACH_NOTICE")))
.bodyValue(BreachNotice(crn = "X000111"))
.exchange()
.expectStatus()
.isCreated

val breachNotice = breachNoticeRepository.findByCrn("X000111").single()
assertThat(breachNotice.crn).isEqualTo("X000111")
assertThat(breachNotice.id).isNotNull()

breachNotice.completedDate = LocalDateTime.now()
breachNoticeRepository.save(breachNotice)

val message: String = "{\"eventType\":\"probation-case.merge.completed\",\"version\":1,\"occurredAt\":\"2025-03-04T10:30:07.329287Z\",\"description\":\"A merge has been completed on the probation case\",\"additionalInformation\":{\"sourceCRN\":\"X000111\",\"targetCRN\":\"X000102\"},\"personReference\":{\"identifiers\":[{\"type\":\"CRN\",\"value\":\"X000102\"}]}}\n"

val responseFuture = inboundSnsClient.publish(
PublishRequest.builder().topicArn("arn:aws:sns:eu-west-2:000000000000:hmppsbreachnoticetopic").message(message).messageAttributes(
mapOf("eventType" to MessageAttributeValue.builder().dataType("String").stringValue("probation-case.merge.completed").build()),
).build(),
)
val response = responseFuture.get(10, TimeUnit.SECONDS)

assertThat(response.messageId()).isNotNull()

Awaitility.await().atMost(10, TimeUnit.SECONDS).untilAsserted {
val breachNoticeUpdated: BreachNoticeEntity = breachNoticeRepository.findById(breachNotice.id).orElse(null)
assertThat(breachNoticeUpdated).isNotNull
assertThat(breachNoticeUpdated.crn).isEqualTo("X000111")
assertThat(breachNoticeUpdated.id).isNotNull()
assertThat(breachNoticeUpdated.reviewRequiredDate).isNull()
assertThat(breachNoticeUpdated.reviewEvent).isNull()
}
}

@Test
fun `unmerge event should update CRN for active breach notice`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_BREACH_NOTICE")))
.bodyValue(BreachNotice(crn = "X000121"))
.exchange()
.expectStatus()
.isCreated

val breachNotice = breachNoticeRepository.findByCrn("X000121").single()
assertThat(breachNotice.crn).isEqualTo("X000121")
assertThat(breachNotice.id).isNotNull()

val message: String = "{\n" +
" \"eventType\":\"probation-case.unmerge.completed\",\n" +
" \"version\":1,\n" +
" \"occurredAt\":\"2025-03-03T12:20:13.6147Z\",\n" +
" \"description\":\"An unmerge has been completed on the probation case\",\n" +
" \"additionalInformation\":{\n" +
" \"reactivatedCRN\":\"X000103\",\n" +
" \"unmergedCRN\":\"X000121\"},\n" +
" \"personReference\":{\n" +
" \"identifiers\":[\n" +
" {\n" +
" \"type\":\"CRN\",\n" +
" \"value\":\"X000121\"\n" +
" }\n" +
" ]\n" +
" }\n" +
"}"

val responseFuture = inboundSnsClient.publish(
PublishRequest.builder().topicArn("arn:aws:sns:eu-west-2:000000000000:hmppsbreachnoticetopic").message(message).messageAttributes(
mapOf("eventType" to MessageAttributeValue.builder().dataType("String").stringValue("probation-case.unmerge.completed").build()),
).build(),
)
val response = responseFuture.get(10, TimeUnit.SECONDS)

assertThat(response.messageId()).isNotNull()

Awaitility.await().atMost(10, TimeUnit.SECONDS).untilAsserted {
val breachNoticeUpdated: BreachNoticeEntity = breachNoticeRepository.findById(breachNotice.id).orElse(null)
assertThat(breachNoticeUpdated).isNotNull
assertThat(breachNoticeUpdated.crn).isEqualTo("X000103")
assertThat(breachNoticeUpdated.id).isNotNull()
assertThat(breachNoticeUpdated.reviewRequiredDate).isNotNull()
assertThat(breachNoticeUpdated.reviewEvent).isEqualTo("UNMERGE")
}
}

@Test
fun `unmerge event should not update CRN for active breach notice`() {
webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_BREACH_NOTICE")))
.bodyValue(BreachNotice(crn = "X000131"))
.exchange()
.expectStatus()
.isCreated

val breachNotice = breachNoticeRepository.findByCrn("X000131").single()
assertThat(breachNotice.crn).isEqualTo("X000131")
assertThat(breachNotice.id).isNotNull()

breachNotice.completedDate = LocalDateTime.now()
breachNoticeRepository.save(breachNotice)

val message: String = "{\n" +
" \"eventType\":\"probation-case.unmerge.completed\",\n" +
" \"version\":1,\n" +
" \"occurredAt\":\"2025-03-03T12:20:13.6147Z\",\n" +
" \"description\":\"An unmerge has been completed on the probation case\",\n" +
" \"additionalInformation\":{\n" +
" \"reactivatedCRN\":\"X000103\",\n" +
" \"unmergedCRN\":\"X000131\"},\n" +
" \"personReference\":{\n" +
" \"identifiers\":[\n" +
" {\n" +
" \"type\":\"CRN\",\n" +
" \"value\":\"X000131\"\n" +
" }\n" +
" ]\n" +
" }\n" +
"}"

val responseFuture = inboundSnsClient.publish(
PublishRequest.builder().topicArn("arn:aws:sns:eu-west-2:000000000000:hmppsbreachnoticetopic").message(message).messageAttributes(
mapOf("eventType" to MessageAttributeValue.builder().dataType("String").stringValue("probation-case.unmerge.completed").build()),
).build(),
)
val response = responseFuture.get(10, TimeUnit.SECONDS)

assertThat(response.messageId()).isNotNull()

Awaitility.await().atMost(10, TimeUnit.SECONDS).untilAsserted {
val breachNoticeUpdated: BreachNoticeEntity = breachNoticeRepository.findById(breachNotice.id).orElse(null)
assertThat(breachNoticeUpdated).isNotNull
assertThat(breachNoticeUpdated.crn).isEqualTo("X000131")
assertThat(breachNoticeUpdated.id).isNotNull()
assertThat(breachNoticeUpdated.reviewRequiredDate).isNull()
assertThat(breachNoticeUpdated.reviewEvent).isNull()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
package uk.gov.justice.digital.hmpps.breachnoticeapi.integration

import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT
import org.springframework.http.HttpHeaders
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.web.reactive.server.WebTestClient
import uk.gov.justice.digital.hmpps.breachnoticeapi.integration.wiremock.GotenbernApiExtension
import uk.gov.justice.digital.hmpps.breachnoticeapi.integration.wiremock.GotenbernApiExtension.Companion.gotenberg
import uk.gov.justice.digital.hmpps.breachnoticeapi.integration.wiremock.HmppsAuthApiExtension
import uk.gov.justice.digital.hmpps.breachnoticeapi.integration.wiremock.HmppsAuthApiExtension.Companion.hmppsAuth
import uk.gov.justice.hmpps.sqs.HmppsQueueService
import uk.gov.justice.hmpps.sqs.HmppsSqsProperties
import uk.gov.justice.hmpps.sqs.MissingQueueException
import uk.gov.justice.hmpps.sqs.MissingTopicException
import uk.gov.justice.hmpps.test.kotlin.auth.JwtAuthorisationHelper

@ExtendWith(GotenbernApiExtension::class)
@ExtendWith(HmppsAuthApiExtension::class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("test")
abstract class IntegrationTestBase {
Expand All @@ -35,19 +26,9 @@ abstract class IntegrationTestBase {
private val inboundTopic by lazy { hmppsQueueService.findByTopicId("hmppsbreachnoticetopic") ?: throw MissingQueueException("HmppsTopic inboundtopic not found") }
protected val inboundSnsClient by lazy { inboundTopic.snsClient }

fun HmppsSqsProperties.inboundTopicConfig() = topics["hmppsbreachnoticetopic"] ?: throw MissingTopicException("hmppsbreachnoticetopic has not been loaded from configuration properties")

internal fun setAuthorisation(
username: String? = "AUTH_ADM",
roles: List<String> = listOf(),
scopes: List<String> = listOf("read"),
): (HttpHeaders) -> Unit = jwtAuthHelper.setAuthorisationHeader(username = username, scope = scopes, roles = roles)

protected fun stubPingWithResponse(status: Int) {
hmppsAuth.stubHealthPing(status)
}

protected fun stubGeneratePdf() {
gotenberg.stubGeneratePdf()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ class PdfGenerationTests : IntegrationTestBase() {

@Test
fun `get PDF should return a 200 response`() {
stubGeneratePdf()

webTestClient.post()
.uri("/breach-notice")
.headers(setAuthorisation(roles = listOf("ROLE_BREACH_NOTICE")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ class HealthCheckTest : IntegrationTestBase() {

@Test
fun `Health page reports ok`() {
stubPingWithResponse(200)

webTestClient.get()
.uri("/health")
.exchange()
Expand Down
Loading

0 comments on commit 9601424

Please sign in to comment.