Skip to content

Commit

Permalink
Optimise creating test applications
Browse files Browse the repository at this point in the history
This commit adds a simple in memory cache for offender details when creating test applications, speeding up the time it takes to create multiple applications
  • Loading branch information
davidatkinsuk committed Jan 22, 2025
1 parent 5499765 commit e470164
Showing 1 changed file with 60 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package uk.gov.justice.digital.hmpps.approvedpremisesapi.seed.cas1

import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import org.json.JSONObject
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -42,6 +45,7 @@ import java.io.IOException
import java.time.LocalDate
import java.time.OffsetDateTime
import java.util.UUID
import java.util.concurrent.TimeUnit

@SuppressWarnings("MagicNumber", "TooGenericExceptionCaught")
@Service
Expand All @@ -50,15 +54,33 @@ class Cas1ApplicationSeedService(
private val bookingRepository: BookingRepository,
private val applicationTimelineNoteService: ApplicationTimelineNoteService,
private val spaceBookingRepository: Cas1SpaceBookingRepository,
private val offenderService: OffenderService,
private val applicationService: ApplicationService,
private val userService: UserService,
private val environmentService: EnvironmentService,
private val assessmentService: AssessmentService,
private val assessmentRepository: AssessmentRepository,
private val postcodeDistrictRepository: PostcodeDistrictRepository,
private val cache: Cas1ApplicationSeedServiceCaches,
) {
private val log = LoggerFactory.getLogger(this::class.java)
companion object {
private val log = LoggerFactory.getLogger(this::class.java)

val ASSESSMENT_DATA_JSON = loadFixtureAsResource("assessment_data.json")
val ASSESSMENT_DOCUMENT_JSON = loadFixtureAsResource("assessment_document.json")
val APPLICATION_DATA_JSON = loadFixtureAsResource("application_data.json")
val APPLICATION_DOCUMENT_JSON: MutableMap<String, Any> = JSONObject(loadFixtureAsResource("application_document.json")).toMap()

private fun loadFixtureAsResource(filename: String): String {
val path = "db/seed/local+dev+test/cas1_application_data/$filename"

try {
return this::class.java.classLoader.getResource(path)?.readText() ?: ""
} catch (e: IOException) {
log.warn("Failed to load seed fixture $path: " + e.message!!)
return "{}"
}
}
}

enum class ApplicationState {
PENDING_SUBMISSION,
Expand Down Expand Up @@ -116,7 +138,7 @@ class Cas1ApplicationSeedService(
deliusUserName: String,
crn: String,
): ApprovedPremisesApplicationEntity {
val personInfo = getPersonInfo(crn)
val personInfo = cache.getPersonInfo(crn)
val createdByUser = (userService.getExistingUserOrCreate(deliusUserName) as GetUserResponse.Success).user

val newApplicationEntity = extractEntityFromCasResult(
Expand All @@ -141,7 +163,7 @@ class Cas1ApplicationSeedService(
apType = ApType.normal,
releaseType = "licence",
arrivalDate = LocalDate.of(2025, 12, 12),
data = loadFixtureAsResource("application_data.json"),
data = APPLICATION_DATA_JSON,
isInapplicable = false,
noticeType = Cas1ApplicationTimelinessCategory.standard,
),
Expand All @@ -167,7 +189,7 @@ class Cas1ApplicationSeedService(
applicationId = application.id,
submitApplication = SubmitApprovedPremisesApplication(
apType = ApType.normal,
translatedDocument = JSONObject(loadFixtureAsResource("application_document.json")).toMap(),
translatedDocument = APPLICATION_DOCUMENT_JSON,
caseManagerIsNotApplicant = false,
isWomensApplication = false,
releaseType = ReleaseTypeOption.licence,
Expand Down Expand Up @@ -204,15 +226,15 @@ class Cas1ApplicationSeedService(
assessmentService.updateAssessment(
assessmentId = getAssessmentId(application),
updatingUser = assessor,
data = loadFixtureAsResource("assessment_data.json"),
data = ASSESSMENT_DATA_JSON,
),
)

ensureEntityFromCasResultIsSuccess(
assessmentService.acceptAssessment(
acceptingUser = assessor,
assessmentId = getAssessmentId(application),
document = loadFixtureAsResource("assessment_document.json"),
document = ASSESSMENT_DOCUMENT_JSON,
placementRequirements = PlacementRequirements(
gender = Gender.male,
type = ApType.normal,
Expand All @@ -239,7 +261,7 @@ class Cas1ApplicationSeedService(
return
}

val personInfo = getPersonInfo(crn)
val personInfo = cache.getPersonInfo(crn)
val offenderDetail = personInfo.offenderDetailSummary

val offlineApplication = applicationService.createOfflineApplication(
Expand Down Expand Up @@ -327,32 +349,37 @@ class Cas1ApplicationSeedService(
),
)
}
}

private fun getPersonInfo(crn: String) =
when (
val personInfoResult = offenderService.getPersonInfoResult(
crn = crn,
deliusUsername = null,
ignoreLaoRestrictions = true,
)
) {
is PersonInfoResult.NotFound, is PersonInfoResult.Unknown -> throw NotFoundProblem(
personInfoResult.crn,
"Offender",
)

is PersonInfoResult.Success.Restricted -> throw ForbiddenProblem()
is PersonInfoResult.Success.Full -> personInfoResult
}
@SuppressWarnings("MagicNumber")
@Service
class Cas1ApplicationSeedServiceCaches(
private val offenderService: OffenderService,
) {

private fun loadFixtureAsResource(filename: String): String {
val path = "db/seed/local+dev+test/cas1_application_data/$filename"
var personInfoCache: LoadingCache<String, PersonInfoResult.Success.Full> = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(object : CacheLoader<String, PersonInfoResult.Success.Full>() {
override fun load(crn: String): PersonInfoResult.Success.Full {
return when (
val personInfoResult = offenderService.getPersonInfoResult(
crn = crn,
deliusUsername = null,
ignoreLaoRestrictions = true,
)
) {
is PersonInfoResult.NotFound, is PersonInfoResult.Unknown -> throw NotFoundProblem(
personInfoResult.crn,
"Offender",
)

is PersonInfoResult.Success.Restricted -> throw ForbiddenProblem()
is PersonInfoResult.Success.Full -> personInfoResult
}
}
})

try {
return this::class.java.classLoader.getResource(path)?.readText() ?: ""
} catch (e: IOException) {
log.warn("Failed to load seed fixture $path: " + e.message!!)
return "{}"
}
}
fun getPersonInfo(crn: String): PersonInfoResult.Success.Full =
personInfoCache.get(crn)
}

0 comments on commit e470164

Please sign in to comment.