Skip to content

Fix functional test create-case retry handling - #2471

Open
gergelykisshmcts wants to merge 11 commits into
masterfrom
deployment_fix
Open

Fix functional test create-case retry handling#2471
gergelykisshmcts wants to merge 11 commits into
masterfrom
deployment_fix

Conversation

@gergelykisshmcts

@gergelykisshmcts gergelykisshmcts commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Jira link

Personal contribution no jira link

Change description

createCase only retried unsuccessful HTTP status codes. A transport-level failure (TLS/socket) was not retried, and SerenityRest turned it into a ResponseStub while recording a failed step on the Serenity event bus. Serenity then skips subsequent @step calls and returns Mockito mocks from them, so a create-case call that was successfully retried still failed the test and surfacing as the misleading claimantPaymentRef NPE seen on master.

  • retry both unsuccessful responses and request exceptions
  • keep the final failure as the cause of the thrown IllegalStateException
  • include the status code and response body when a call returns non-201
  • issue the request with plain RestAssured so a recovered retry no longer records a failed step and poisons later steps
  • assert the first fee payment reference is non-null before dereferencing it

Testing done

Local test runs

Security Vulnerability Assessment

CVE Suppression: Are there any CVEs present in the codebase (either newly introduced or pre-existing) that are being intentionally suppressed or ignored by this commit?

  • Yes
  • No

Checklist

  • commit messages are meaningful and follow good commit message guidelines
  • README and other documentation has been updated / added (if needed)
  • tests have been updated / new tests has been added (if needed)
  • Does this PR introduce a breaking change

PCS checklist

  • New functional test classes carry the gating annotations (@EnabledIfEnvironmentVariable(named = "CCD_ENABLED", ...) + shutter guard) unless they must run on unlabelled PRs (HDPI-8084)
  • Infrastructure / chart / suppression changes have a second pair of eyes from the service admins (HDPI-8153)

createCase only retried unsuccessful HTTP status codes. A transport-level
failure (TLS/socket) was not retried, and SerenityRest turned it into a
ResponseStub while recording a failed step on the Serenity event bus.
Serenity then skips subsequent @step calls and returns Mockito mocks from
them, so a create-case call that was successfully retried still failed the
test - surfacing as the misleading claimantPaymentRef NPE seen on master.

- retry both unsuccessful responses and request exceptions
- keep the final failure as the cause of the thrown IllegalStateException
- include the status code and response body when a call returns non-201
- issue the request with plain RestAssured so a recovered retry no longer
  records a failed step and poisons later steps
- assert the first fee payment reference is non-null before dereferencing it
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

CCD diff summary

👉 Full report: https://github.com/hmcts/pcs-api/actions/runs/32866142823?check_suite_focus=true

No change

@tvr-hmcts tvr-hmcts left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. :)

Some thoughts ... perhaps beyond the fix though.

Somethings can not be retried so should they be checked for and just skip out earlier on? 400 / 401's etc

Also there is no back off / wait etc period before hitting again in that loop. Would that help at all in some circumstances?

@gergelykisshmcts

Copy link
Copy Markdown
Contributor Author

Cool. :)

Some thoughts ... perhaps beyond the fix though.

Somethings can not be retried so should they be checked for and just skip out earlier on? 400 / 401's etc

Also there is no back off / wait etc period before hitting again in that loop. Would that help at all in some circumstances?

Yep, both good points. I think it makes sense to tighten this while we’re here.
I’ll make the retry policy explicit so normal 4xx responses fail immediately rather than being retried, while transport failures 408 429 5xx remain retryable. I’ll also add a small backoff between attempts so we don’t immediately hit the same transient condition again.
I’ll keep it small since this is just to make functional-test more relaible rather than something I want to turn into a retry framework :)

Comment thread src/functionalTest/java/uk/gov/hmcts/reform/pcs/functional/steps/ApiSteps.java Outdated
POST /testing-support/{country}/create-case has no idempotency key and no
duplicate detection. The CCD case is created part-way through the server-side
orchestration by submitCaseCreation, and the resume event, court allocation,
issue date and access-code steps all run after that, so a failure response can
be returned with the case already created. Replaying the request could create a
second case.

- issue the request once, via SerenityRest so reporting is unchanged
- report the real status code and truncated response body on failure
- fail with a clear message when no usable response was read, rather than
  replaying a request that may already have been processed
Conflict in ApiSteps.java: master reformatted the old createCase retry loop
while this branch replaced it with a single-shot request. Kept the single-shot
version and master's dataStoreUrl field, getInternalCaseDetails rename and new
validateEventData step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants