Skip to content

Commit c0cc133

Browse files
add gateway logic and tests (#712)
1 parent c3da310 commit c0cc133

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsintegrationapi/gateways/NomisGateway.kt

+25
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.NomisSenten
3737
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.NomisSentenceSummary
3838
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.NomisTransactionResponse
3939
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.NomisTransactionTransferResponse
40+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.visits.VisitBalances
4041

4142
@Component
4243
class NomisGateway(
@@ -477,6 +478,30 @@ class NomisGateway(
477478
}
478479
}
479480

481+
fun getVisitBalances(offenderNumber: String): Response<VisitBalances?> {
482+
val result =
483+
webClient.request<VisitBalances>(
484+
HttpMethod.GET,
485+
"/api/bookings/offenderNo/$offenderNumber/visit/balances",
486+
authenticationHeader(),
487+
UpstreamApi.NOMIS,
488+
badRequestAsError = true,
489+
)
490+
491+
return when (result) {
492+
is WebClientWrapperResponse.Success -> {
493+
Response(data = result.data)
494+
}
495+
496+
is WebClientWrapperResponse.Error -> {
497+
Response(
498+
data = null,
499+
errors = result.errors,
500+
)
501+
}
502+
}
503+
}
504+
480505
private fun authenticationHeader(): Map<String, String> {
481506
val token = hmppsAuthGateway.getClientToken("NOMIS")
482507

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.visits
2+
3+
data class VisitBalances(
4+
val remainingVo: Long,
5+
val remainingPvo: Long,
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.nomis
2+
3+
import io.kotest.core.spec.style.DescribeSpec
4+
import io.kotest.matchers.collections.shouldHaveSize
5+
import io.kotest.matchers.nulls.shouldNotBeNull
6+
import io.kotest.matchers.shouldBe
7+
import org.mockito.Mockito
8+
import org.mockito.internal.verification.VerificationModeFactory
9+
import org.mockito.kotlin.verify
10+
import org.mockito.kotlin.whenever
11+
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer
12+
import org.springframework.http.HttpStatus
13+
import org.springframework.test.context.ActiveProfiles
14+
import org.springframework.test.context.ContextConfiguration
15+
import org.springframework.test.context.bean.override.mockito.MockitoBean
16+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.removeWhitespaceAndNewlines
17+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.HmppsAuthGateway
18+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.NomisGateway
19+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.HmppsAuthMockServer
20+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.mockservers.NomisApiMockServer
21+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi
22+
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError
23+
24+
@ActiveProfiles("test")
25+
@ContextConfiguration(
26+
initializers = [ConfigDataApplicationContextInitializer::class],
27+
classes = [NomisGateway::class],
28+
)
29+
class GetVisitBalancesForPersonTest(
30+
@MockitoBean val hmppsAuthGateway: HmppsAuthGateway,
31+
val nomisGateway: NomisGateway,
32+
) : DescribeSpec({
33+
val nomisApiMockServer = NomisApiMockServer()
34+
val offenderNumber = "A7777ZZ"
35+
val visitBalancesPath = "/api/bookings/offenderNo/$offenderNumber/visit/balances"
36+
37+
beforeEach {
38+
nomisApiMockServer.start()
39+
nomisApiMockServer.stubNomisApiResponse(
40+
visitBalancesPath,
41+
"""
42+
{
43+
"remainingVo": 1073741824,
44+
"remainingPvo": 1073741824,
45+
"latestIepAdjustDate": "2025-03-04",
46+
"latestPrivIepAdjustDate": "2025-03-04"
47+
}
48+
""".removeWhitespaceAndNewlines(),
49+
)
50+
51+
Mockito.reset(hmppsAuthGateway)
52+
whenever(hmppsAuthGateway.getClientToken("NOMIS")).thenReturn(HmppsAuthMockServer.TOKEN)
53+
}
54+
55+
afterTest {
56+
nomisApiMockServer.stop()
57+
}
58+
59+
it("authenticates using HMPPS Auth with credentials") {
60+
nomisGateway.getVisitBalances(offenderNumber)
61+
62+
verify(hmppsAuthGateway, VerificationModeFactory.times(1)).getClientToken("NOMIS")
63+
}
64+
65+
it("returns visit balances for the matching offender number") {
66+
val response = nomisGateway.getVisitBalances(offenderNumber)
67+
68+
response.data.shouldNotBeNull()
69+
response.data?.remainingVo.shouldBe(1073741824)
70+
}
71+
72+
it("returns an error when 400 Bad Request is returned because of an invalid request") {
73+
nomisApiMockServer.stubNomisApiResponse(visitBalancesPath, "", HttpStatus.BAD_REQUEST)
74+
75+
val response = nomisGateway.getVisitBalances(offenderNumber)
76+
77+
response.errors.shouldHaveSize(1)
78+
response.errors
79+
.first()
80+
.causedBy
81+
.shouldBe(UpstreamApi.NOMIS)
82+
response.errors
83+
.first()
84+
.type
85+
.shouldBe(UpstreamApiError.Type.BAD_REQUEST)
86+
}
87+
88+
it("returns an error when 404 Not Found is returned because no person is found") {
89+
nomisApiMockServer.stubNomisApiResponse(visitBalancesPath, "", HttpStatus.NOT_FOUND)
90+
91+
val response = nomisGateway.getVisitBalances(offenderNumber)
92+
93+
response.errors.shouldHaveSize(1)
94+
response.errors
95+
.first()
96+
.causedBy
97+
.shouldBe(UpstreamApi.NOMIS)
98+
response.errors
99+
.first()
100+
.type
101+
.shouldBe(UpstreamApiError.Type.ENTITY_NOT_FOUND)
102+
}
103+
})

0 commit comments

Comments
 (0)