From 732702173e8bfeeb3c2631cf6f5baa33b9ee07e8 Mon Sep 17 00:00:00 2001 From: dfitchett <135860892+dfitchett@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:51:07 -0800 Subject: [PATCH] Added end to end tests with mocks --- .github/workflows/ee-ep-merge-end-to-end.yml | 4 + domain-ee/ee-ep-merge-app/build.gradle | 12 + .../ee-ep-merge-app/end_to_end/__init__.py | 0 .../ee-ep-merge-app/end_to_end/conftest.py | 21 ++ .../test_process_new_merge_request.py | 165 +++++++++ .../end_to_end/test_restart.py | 126 +++++++ .../end_to_end/test_resume_at_add_note.py | 91 +++++ .../end_to_end/test_resume_at_cancel.py | 97 ++++++ .../config/ClaimIdConstants.java | 23 ++ .../controller/BaseController.java | 1 - .../controller/ClaimsController.java | 11 +- .../controller/ContentionsController.java | 11 +- .../LifecycleStatusesController.java | 5 +- .../src/main/resources/mock-claims.json | 325 +++++++++++++++++- 14 files changed, 880 insertions(+), 12 deletions(-) create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/__init__.py create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/conftest.py create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/test_process_new_merge_request.py create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/test_restart.py create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_add_note.py create mode 100644 domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_cancel.py create mode 100644 mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/config/ClaimIdConstants.java diff --git a/.github/workflows/ee-ep-merge-end-to-end.yml b/.github/workflows/ee-ep-merge-end-to-end.yml index 9435cc3970..07bc1b3a3f 100644 --- a/.github/workflows/ee-ep-merge-end-to-end.yml +++ b/.github/workflows/ee-ep-merge-end-to-end.yml @@ -128,6 +128,10 @@ jobs: exit 10 fi + - name: 'Run End 2 End Tests' + shell: bash + run: | + ./gradlew :domain-ee:ee-ep-merge-app:endToEndTest - name: 'Clean shutdown of all containers' if: always() diff --git a/domain-ee/ee-ep-merge-app/build.gradle b/domain-ee/ee-ep-merge-app/build.gradle index 40419bc40f..cd06cfe360 100644 --- a/domain-ee/ee-ep-merge-app/build.gradle +++ b/domain-ee/ee-ep-merge-app/build.gradle @@ -14,3 +14,15 @@ tasks.register('integrationTest', Test) { dependsOn 'integrationPytest' group = 'verification' } + +// Runs pytest end-to-end tests when './gradlew integration-test' is run +tasks.register('endToEndPytest', PythonTask) { + dependsOn 'pyflake8' + module = 'pytest' + command = './end_to_end' +} + +tasks.register('endToEndTest', Test) { + dependsOn 'endToEndPytest' + group = 'verification' +} diff --git a/domain-ee/ee-ep-merge-app/end_to_end/__init__.py b/domain-ee/ee-ep-merge-app/end_to_end/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/domain-ee/ee-ep-merge-app/end_to_end/conftest.py b/domain-ee/ee-ep-merge-app/end_to_end/conftest.py new file mode 100644 index 0000000000..a8bba9e73f --- /dev/null +++ b/domain-ee/ee-ep-merge-app/end_to_end/conftest.py @@ -0,0 +1,21 @@ +import pytest +import pytest_asyncio +from src.python_src.api import on_shut_down, on_start_up +from src.python_src.service.job_store import job_store + + +@pytest.fixture(autouse=True) +async def job_store_fixture(request): + def finalizer(): + job_store.clear() + + request.addfinalizer(finalizer) + + return job_store + + +@pytest_asyncio.fixture(autouse=True, scope="session") +async def endpoint_lifecycle(): + await on_start_up() + yield + await on_shut_down() diff --git a/domain-ee/ee-ep-merge-app/end_to_end/test_process_new_merge_request.py b/domain-ee/ee-ep-merge-app/end_to_end/test_process_new_merge_request.py new file mode 100644 index 0000000000..9a7f7c117b --- /dev/null +++ b/domain-ee/ee-ep-merge-app/end_to_end/test_process_new_merge_request.py @@ -0,0 +1,165 @@ +import asyncio + +import pytest +from httpx import AsyncClient +from src.python_src.api import app +from src.python_src.schema.merge_job import JobState +from src.python_src.service.job_store import job_store + +ACCEPTABLE_JOB_PROCESSING_DURATION = 0.2 + +PENDING_CLAIM_ID = 10000 +EP400_WITH_DUPLICATE = 10001 +EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE = 10002 +EP400_WITH_DIFFERENT_CLAIMANT_TEXT = 10003 +EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE = 10004 +EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES = 10005 + +CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS = 5001 +CLAIM_ID_ERROR_AT_CANCEL_CLAIM = 5002 +CLAIM_ID_ERROR_AT_SET_TSOJ = 5003 +CLAIM_ID_ERROR_AT_GET_CONTENTIONS = 5004 +CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS = 5005 +CLAIM_ID_ERROR_AT_CREATE_CONTENTIONS = 5006 + + +def assert_response(response, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0, + status_code: int = 200): + assert response.status_code == status_code + response_json = response.json() + assert response_json is not None + job = response_json['job'] + assert job['pending_claim_id'] == pending_claim_id + assert job['ep400_claim_id'] == ep400_claim_id + assert job['state'] == expected_state + if expected_error_state is None: + assert 'error_state' not in job + else: + assert job['error_state'] == expected_error_state + if expected_num_errors == 0: + assert 'messages' not in job + else: + assert len(job['messages']) == expected_num_errors + return response_json + + +def assert_job(job_id, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0): + job = job_store.get_merge_job(job_id) + assert job is not None + assert job.pending_claim_id == pending_claim_id + assert job.ep400_claim_id == ep400_claim_id + assert job.state == expected_state + assert job.error_state == expected_error_state + + if expected_num_errors == 0: + assert job.messages is None + else: + assert len(job.messages) == expected_num_errors + + +def assert_response_and_job(response, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0, + status_code: int = 200): + json = assert_response(response, pending_claim_id, ep400_claim_id, expected_state, expected_error_state, expected_num_errors, status_code) + job_id = json['job']['job_id'] + assert_job(job_id, pending_claim_id, ep400_claim_id, expected_state, expected_error_state, expected_num_errors) + + +async def submit_request_and_process(client, pending_claim_id, ep400_claim_id): + request = {"pending_claim_id": pending_claim_id, "ep400_claim_id": ep400_claim_id} + response = await client.post(url="/merge", json=request) + + response_json = assert_response(response, pending_claim_id, ep400_claim_id, JobState.PENDING.value, status_code=202) + job_id = response_json['job']['job_id'] + + await asyncio.sleep(ACCEPTABLE_JOB_PROCESSING_DURATION) + + response = await client.get(url=f"/merge/{job_id}") + + return response + + +class TestSuccess: + + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id", [ + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DUPLICATE, id="with duplicate contention"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE, id="with different contention type code"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CLAIMANT_TEXT, id="with different claimant text"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE, id="with one duplicate, one not"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, id="with with no duplicates"), + ]) + async def test(self, pending_claim_id, ep400_claim_id): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await submit_request_and_process(client, pending_claim_id, ep400_claim_id) + assert_response_and_job(response, pending_claim_id, ep400_claim_id, JobState.COMPLETED_SUCCESS) + + +class TestError: + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id,expected_error_state,expected_num_errors", [ + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM, + 1, + id="fail to get pending claim details"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM_CONTENTIONS, + 1, + id="fail to get pending claim contentions"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + JobState.RUNNING_GET_EP400_CLAIM_CONTENTIONS, + 1, + id="fail to get ep400 claim contentions"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_SET_TSOJ, + JobState.RUNNING_SET_TEMP_STATION_OF_JURISDICTION, + 1, + id="fail to set tsoj on ep400"), + pytest.param(CLAIM_ID_ERROR_AT_CREATE_CONTENTIONS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_MOVE_CONTENTIONS_TO_PENDING_CLAIM, + 1, + id="fail to move claim contentions to pending claim"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_CANCEL_CLAIM, + JobState.RUNNING_CANCEL_EP400_CLAIM, + 1, + id="fail to cancel ep400 claim"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_CONTENTIONS_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim contentions") + ]) + async def test(self, job_store_fixture, pending_claim_id, ep400_claim_id, expected_error_state, expected_num_errors): + async with AsyncClient(app=app, base_url="http://test") as client: + response = await submit_request_and_process(client, pending_claim_id, ep400_claim_id) + assert_response_and_job(response, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + expected_state=JobState.COMPLETED_ERROR, + expected_error_state=expected_error_state, + expected_num_errors=expected_num_errors, + status_code=200) diff --git a/domain-ee/ee-ep-merge-app/end_to_end/test_restart.py b/domain-ee/ee-ep-merge-app/end_to_end/test_restart.py new file mode 100644 index 0000000000..637b76907f --- /dev/null +++ b/domain-ee/ee-ep-merge-app/end_to_end/test_restart.py @@ -0,0 +1,126 @@ +import asyncio +from datetime import datetime +from uuid import uuid4 + +import pytest +from src.python_src.api import resume_job_state_machine +from src.python_src.schema.merge_job import JobState, MergeJob +from src.python_src.service.job_store import job_store + +PENDING_CLAIM_ID = 10000 +EP400_WITH_DUPLICATE = 10001 +EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE = 10002 +EP400_WITH_DIFFERENT_CLAIMANT_TEXT = 10003 +EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE = 10004 +EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES = 10005 + +CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS = 5001 +CLAIM_ID_ERROR_AT_CANCEL_CLAIM = 5002 +CLAIM_ID_ERROR_AT_SET_TSOJ = 5003 +CLAIM_ID_ERROR_AT_GET_CONTENTIONS = 5004 +CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS = 5005 +CLAIM_ID_ERROR_AT_CREATE_CONTENTIONS = 5006 + +NOW = datetime.now() + + +def assert_job(job_id, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0): + job = job_store.get_merge_job(job_id) + assert job is not None + assert job.pending_claim_id == pending_claim_id + assert job.ep400_claim_id == ep400_claim_id + assert job.state == expected_state + assert job.error_state == expected_error_state + + if expected_num_errors == 0: + assert job.messages is None + else: + assert len(job.messages) == expected_num_errors + + +@pytest.mark.parametrize("starting_state", [state for state in JobState.incomplete_states() if state not in [JobState.RUNNING_CANCEL_EP400_CLAIM, JobState.RUNNING_ADD_CLAIM_NOTE_TO_EP400]]) +class TestRestart: + class TestSuccess: + + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id", [ + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DUPLICATE, id="with duplicate contention"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE, id="with different contention type code"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CLAIMANT_TEXT, id="with different claimant text"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE, id="with one duplicate, one not"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, id="with with no duplicates"), + ]) + async def test(self, starting_state, pending_claim_id, ep400_claim_id): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=starting_state, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_SUCCESS) + + class TestError: + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id,expected_error_state,expected_num_errors", [ + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM, + 1, + id="fail to get pending claim details"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM_CONTENTIONS, + 1, + id="fail to get pending claim contentions"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + JobState.RUNNING_GET_EP400_CLAIM_CONTENTIONS, + 1, + id="fail to get ep400 claim contentions"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_SET_TSOJ, + JobState.RUNNING_SET_TEMP_STATION_OF_JURISDICTION, + 1, + id="fail to set tsoj on ep400"), + pytest.param(CLAIM_ID_ERROR_AT_CREATE_CONTENTIONS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_MOVE_CONTENTIONS_TO_PENDING_CLAIM, + 1, + id="fail to move claim contentions to pending claim"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_CANCEL_CLAIM, + JobState.RUNNING_CANCEL_EP400_CLAIM, + 1, + id="fail to cancel ep400 claim"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CONTENTIONS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_CONTENTIONS_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim contentions") + ]) + async def test(self, starting_state, pending_claim_id, ep400_claim_id, expected_error_state, expected_num_errors): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=starting_state, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_ERROR, expected_error_state, expected_num_errors) diff --git a/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_add_note.py b/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_add_note.py new file mode 100644 index 0000000000..e69ffccf8c --- /dev/null +++ b/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_add_note.py @@ -0,0 +1,91 @@ +import asyncio +from datetime import datetime +from uuid import uuid4 + +import pytest +from src.python_src.api import resume_job_state_machine +from src.python_src.schema.merge_job import JobState, MergeJob +from src.python_src.service.job_store import job_store + +PENDING_CLAIM_ID = 10000 +EP400_WITH_DUPLICATE = 10001 +EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE = 10002 +EP400_WITH_DIFFERENT_CLAIMANT_TEXT = 10003 +EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE = 10004 +EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES = 10005 + +CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS = 5001 +CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS = 5005 + +NOW = datetime.now() + + +def assert_job(job_id, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0): + job = job_store.get_merge_job(job_id) + assert job is not None + assert job.pending_claim_id == pending_claim_id + assert job.ep400_claim_id == ep400_claim_id + assert job.state == expected_state + assert job.error_state == expected_error_state + + if expected_num_errors == 0: + assert job.messages is None + else: + assert len(job.messages) == expected_num_errors + + +class TestSuccess: + + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id", [ + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DUPLICATE, id="with duplicate contention"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE, id="with different contention type code"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CLAIMANT_TEXT, id="with different claimant text"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE, id="with one duplicate, one not"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, id="with with no duplicates"), + ]) + async def test(self, pending_claim_id, ep400_claim_id): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=JobState.RUNNING_ADD_CLAIM_NOTE_TO_EP400, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_SUCCESS) + + +class TestError: + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id,expected_error_state,expected_num_errors", [ + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM, + 1, + id="fail to get pending claim details"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim"), + ]) + async def test(self, pending_claim_id, ep400_claim_id, expected_error_state, expected_num_errors): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=JobState.RUNNING_ADD_CLAIM_NOTE_TO_EP400, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_ERROR, expected_error_state, expected_num_errors) diff --git a/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_cancel.py b/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_cancel.py new file mode 100644 index 0000000000..da75fc8ee1 --- /dev/null +++ b/domain-ee/ee-ep-merge-app/end_to_end/test_resume_at_cancel.py @@ -0,0 +1,97 @@ +import asyncio +from datetime import datetime +from uuid import uuid4 + +import pytest +from src.python_src.api import resume_job_state_machine +from src.python_src.schema.merge_job import JobState, MergeJob +from src.python_src.service.job_store import job_store + +PENDING_CLAIM_ID = 10000 +EP400_WITH_DUPLICATE = 10001 +EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE = 10002 +EP400_WITH_DIFFERENT_CLAIMANT_TEXT = 10003 +EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE = 10004 +EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES = 10005 + +CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS = 5001 +CLAIM_ID_ERROR_AT_CANCEL_CLAIM = 5002 +CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS = 5005 + +NOW = datetime.now() + + +def assert_job(job_id, + pending_claim_id, + ep400_claim_id, + expected_state: JobState, + expected_error_state: JobState | None = None, + expected_num_errors: int = 0): + job = job_store.get_merge_job(job_id) + assert job is not None + assert job.pending_claim_id == pending_claim_id + assert job.ep400_claim_id == ep400_claim_id + assert job.state == expected_state + assert job.error_state == expected_error_state + + if expected_num_errors == 0: + assert job.messages is None + else: + assert len(job.messages) == expected_num_errors + + +class TestSuccess: + + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id", [ + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DUPLICATE, id="with duplicate contention"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CONTENTION_TYPE_CODE, id="with different contention type code"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_DIFFERENT_CLAIMANT_TEXT, id="with different claimant text"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_ONE_DUPLICATE, id="with one duplicate, one not"), + pytest.param(PENDING_CLAIM_ID, EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, id="with with no duplicates"), + ]) + async def test(self, pending_claim_id, ep400_claim_id): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=JobState.RUNNING_CANCEL_EP400_CLAIM, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_SUCCESS) + + +class TestError: + @pytest.mark.asyncio(scope="session") + @pytest.mark.parametrize("pending_claim_id,ep400_claim_id,expected_error_state,expected_num_errors", [ + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + EP400_WITH_MULTI_CONTENTION_NO_DUPLICATES, + JobState.RUNNING_GET_PENDING_CLAIM, + 1, + id="fail to get pending claim details"), + pytest.param(PENDING_CLAIM_ID, + CLAIM_ID_ERROR_AT_CANCEL_CLAIM, + JobState.RUNNING_CANCEL_EP400_CLAIM, + 1, + id="fail to cancel ep400 claim"), + pytest.param(CLAIM_ID_ERROR_AT_GET_CLAIM_DETAILS, + CLAIM_ID_ERROR_AT_UPDATE_CONTENTIONS, + JobState.RUNNING_GET_PENDING_CLAIM_FAILED_REMOVE_SPECIAL_ISSUE, + 2, + id="fail to remove special issues from ep400 claim after failing to get pending claim"), + ]) + async def test(self, pending_claim_id, ep400_claim_id, expected_error_state, expected_num_errors): + job_id = uuid4() + job = MergeJob(job_id=job_id, + pending_claim_id=pending_claim_id, + ep400_claim_id=ep400_claim_id, + state=JobState.RUNNING_CANCEL_EP400_CLAIM, + created_at=NOW, + updated_at=NOW) + job_store.submit_merge_job(job) + + await asyncio.get_event_loop().run_in_executor(None, resume_job_state_machine, job) + assert_job(job_id, pending_claim_id, ep400_claim_id, JobState.COMPLETED_ERROR, expected_error_state, expected_num_errors) diff --git a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/config/ClaimIdConstants.java b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/config/ClaimIdConstants.java new file mode 100644 index 0000000000..3b903effd2 --- /dev/null +++ b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/config/ClaimIdConstants.java @@ -0,0 +1,23 @@ +package gov.va.vro.mockbipclaims.config; + +public class ClaimIdConstants { + + public static final int CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 = 500; + + // GET /claims/{claimId} + public static final int CLAIM_ID_GET_CLAIM_DETAILS_YIELDS_500 = 5001; + // PUT /claims/{claimId}/cancel + public static final int CLAIM_ID_CANCEL_CLAIM_YIELDS_500 = 5002; + // PUT /claims/{claimId}/temporary_station_of_jurisdiction + public static final int CLAIM_ID_SET_TSOJ_YIELDS_500 = 5003; + + // GET /claims/{claimId}/contentions + public static final int CLAIM_ID_GET_CONTENTIONS_YIELDS_500 = 5004; + // PUT /claims/{claimId}/contentions + public static final int CLAIM_ID_UPDATE_CONTENTIONS_YIELDS_500 = 5005; + // POST /claims/{claimId}/contentions + public static final int CLAIM_ID_CREATE_CONTENTIONS_YIELDS_500 = 5006; + + // PUT /claims/{claimId}/lifecycle_status + public static final int CLAIM_ID_UPDATE_LIFECYCLE_STATUS_YIELDS_500 = 5007; +} diff --git a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/BaseController.java b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/BaseController.java index 84dbf104a1..f5d2728271 100644 --- a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/BaseController.java +++ b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/BaseController.java @@ -8,7 +8,6 @@ import java.time.OffsetDateTime; public class BaseController { - protected static final int CLAIM_YIELDS_500 = 500; protected ResponseEntity create200(T response) { return new ResponseEntity<>(response, HttpStatus.OK); diff --git a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ClaimsController.java b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ClaimsController.java index 54fff288e2..418d6d1ec3 100644 --- a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ClaimsController.java +++ b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ClaimsController.java @@ -1,5 +1,10 @@ package gov.va.vro.mockbipclaims.controller; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_ALL_ENDPOINTS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_CANCEL_CLAIM_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_GET_CLAIM_DETAILS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_SET_TSOJ_YIELDS_500; + import gov.va.vro.mockbipclaims.api.ClaimsApi; import gov.va.vro.mockbipclaims.model.bip.request.CloseClaimRequest; import gov.va.vro.mockbipclaims.model.bip.request.PutTemporaryStationOfJurisdictionRequest; @@ -29,7 +34,7 @@ public ResponseEntity getClaimById(Long claimId) { if (item == null) { return createClaim404(response, claimId); } - if (claimId == CLAIM_YIELDS_500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_GET_CLAIM_DETAILS_YIELDS_500) { return create500(response); } @@ -50,7 +55,7 @@ public ResponseEntity cancelClaimById( return createClaim404(response, claimId); } - if (claimId == CLAIM_YIELDS_500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_CANCEL_CLAIM_YIELDS_500) { return create500(response); } @@ -80,7 +85,7 @@ public ResponseEntity cancelClaimById( return createClaim404(response, claimId); } - if (claimId == CLAIM_YIELDS_500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_SET_TSOJ_YIELDS_500) { return create500(response); } diff --git a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ContentionsController.java b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ContentionsController.java index 6bf329a55f..b8895dde9a 100644 --- a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ContentionsController.java +++ b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/ContentionsController.java @@ -1,5 +1,10 @@ package gov.va.vro.mockbipclaims.controller; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_ALL_ENDPOINTS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_CREATE_CONTENTIONS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_GET_CONTENTIONS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_UPDATE_CONTENTIONS_YIELDS_500; + import gov.va.vro.mockbipclaims.api.ContentionsApi; import gov.va.vro.mockbipclaims.mapper.ContentionMapper; import gov.va.vro.mockbipclaims.model.bip.ContentionSummary; @@ -43,7 +48,7 @@ public ResponseEntity createContentionsForClaim( if (item == null) { return createClaim400(response, claimId); } - if (claimId == 500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_CREATE_CONTENTIONS_YIELDS_500) { return create500(response); } @@ -72,7 +77,7 @@ public ResponseEntity getContentionsForClaim(Long c if (item == null) { return createClaim404(response, claimId); } - if (claimId == 500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_GET_CONTENTIONS_YIELDS_500) { return create500(response); } @@ -104,7 +109,7 @@ public ResponseEntity updateContentions( // Non-existent claim id yields 400, not 404 return createClaim400(response, claimId); } - if (claimId == 500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_UPDATE_CONTENTIONS_YIELDS_500) { return create500(response); } diff --git a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/LifecycleStatusesController.java b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/LifecycleStatusesController.java index 79c38b1c3b..85010aa0a1 100644 --- a/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/LifecycleStatusesController.java +++ b/mocks/mock-bip-claims-api/src/main/java/gov/va/vro/mockbipclaims/controller/LifecycleStatusesController.java @@ -1,5 +1,8 @@ package gov.va.vro.mockbipclaims.controller; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_ALL_ENDPOINTS_YIELDS_500; +import static gov.va.vro.mockbipclaims.config.ClaimIdConstants.CLAIM_ID_UPDATE_LIFECYCLE_STATUS_YIELDS_500; + import gov.va.vro.mockbipclaims.api.LifecycleStatusesApi; import gov.va.vro.mockbipclaims.model.bip.request.UpdateClaimLifecycleStatusRequest; import gov.va.vro.mockbipclaims.model.bip.response.UpdateClaimLifecycleStatusResponse; @@ -30,7 +33,7 @@ public ResponseEntity updateClaimLifecycleSt if (item == null) { return createClaim404(response, claimId); } - if (claimId == CLAIM_YIELDS_500) { + if (claimId == CLAIM_ID_ALL_ENDPOINTS_YIELDS_500 || claimId == CLAIM_ID_UPDATE_LIFECYCLE_STATUS_YIELDS_500) { return create500(response); } diff --git a/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json b/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json index 0f9a8601a6..bafc48004b 100644 --- a/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json +++ b/mocks/mock-bip-claims-api/src/main/resources/mock-claims.json @@ -47,10 +47,10 @@ "medicalInd": true, "beginDate": "2023-01-01T00:00:00Z", "contentionTypeCode": "NEW", - "classificationType": 1250, - "diagnosticTypeCode": "6100", - "claimantText": "tendinitis/bilateral", - "contentionId": "1011", + "classificationType": 6850, + "diagnosticTypeCode": "6260", + "claimantText": "tinnitus", + "contentionId": "1012", "lastModified": "2023-01-01T00:00:01Z" } ] @@ -782,5 +782,322 @@ ] } ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Pending 010 w/ tempStationOfJurisdiction set to 398" + ], + "claimDetail": { + "claimId": 10000, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "010" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - EP 400 w/ contention with duplicate contention from claim 10000" + ], + "claimDetail": { + "claimId": 10001, + "phase": "Claim Received", + "endProductCode": "400", + "claimLifecycleStatus": "Open" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "2", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - EP 400 w/ contention with different contention type code as claim 10000" + ], + "claimDetail": { + "claimId": 10002, + "phase": "Claim Received", + "endProductCode": "400", + "claimLifecycleStatus": "Open" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "INCREASE", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "3", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - EP 400 w/ contention with different contention as claim 10000" + ], + "claimDetail": { + "claimId": 10003, + "phase": "Claim Received", + "endProductCode": "400", + "claimLifecycleStatus": "Open" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 6850, + "diagnosticTypeCode": "6260", + "claimantText": "tinnitus", + "contentionId": "4", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - EP 400 w/ multiple contentions w/ one duplicate from claim 10000" + ], + "claimDetail": { + "claimId": 10004, + "phase": "Claim Received", + "endProductCode": "400", + "claimLifecycleStatus": "Open" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "5", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + }, + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 6850, + "diagnosticTypeCode": "6260", + "claimantText": "tinnitus", + "contentionId": "6", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - EP 400 w/ multiple contentions w/ no duplicates in claim 10000" + ], + "claimDetail": { + "claimId": 10005, + "phase": "Claim Received", + "endProductCode": "400", + "claimLifecycleStatus": "Open" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "INCREASE", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "7", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + }, + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 6850, + "diagnosticTypeCode": "6260", + "claimantText": "tinnitus", + "contentionId": "8", + "lastModified": "2023-01-01T00:00:01Z", + "specialIssueCodes": [ + "EMP" + ] + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at get claim details" + ], + "claimDetail": { + "claimId": 5001, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "010" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at cancel claim" + ], + "claimDetail": { + "claimId": 5002, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "400" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at set temporary station of jurisdiction" + ], + "claimDetail": { + "claimId": 5003, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "400" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at get claim contentions" + ], + "claimDetail": { + "claimId": 5004, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "010" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at update claim contentions" + ], + "claimDetail": { + "claimId": 5005, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "400" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] + }, + { + "description": [ + "Employee Experience EP Merge End 2 End Testing - Fails at create claim contentions" + ], + "claimDetail": { + "claimId": 5006, + "phase": "Claim Received", + "tempStationOfJurisdiction": "398", + "endProductCode": "010" + }, + "contentions": [ + { + "medicalInd": true, + "beginDate": "2023-01-01T00:00:00Z", + "contentionTypeCode": "NEW", + "classificationType": 1250, + "diagnosticTypeCode": "6100", + "claimantText": "tendinitis/bilateral", + "contentionId": "1", + "lastModified": "2023-01-01T00:00:01Z" + } + ] } ]