From a21afb9e8ced794f2a616ee3152ccf9d4fd30bf2 Mon Sep 17 00:00:00 2001 From: Jorge Lopez <49923512+jorg3lopez@users.noreply.github.com> Date: Wed, 10 Jan 2024 00:46:28 -0800 Subject: [PATCH] Test Coverage for #672 (#756) * unit tests: PartnerMetadataOrchestrator: getMetadat retrieves metadata successfully when receiver is present and sentSubmissionId is missing. SuncRetryTask : should handle thread interruption. * unit test for readMetadata * readMetadata unhappy path unit test * saveMetadata happy path works - unit test * saveMetadata unhappy path works - unit test * refactoring variable type to def * unit test: convertAndSend logs event when submissionId is null * added sentSubmissionId to reflect changes in main --- .../PartnerMetadataOrchestratorTest.groovy | 33 ++++-- .../etor/orders/SendOrderUsecaseTest.groovy | 15 +++ .../DatabasePartnerMetadataStorageTest.groovy | 108 ++++++++++++++++++ .../utils/SyncRetryTaskTest.groovy | 28 ++++- 4 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/database/DatabasePartnerMetadataStorageTest.groovy diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/metadata/PartnerMetadataOrchestratorTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/metadata/PartnerMetadataOrchestratorTest.groovy index d8b43808c..1970a7d16 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/metadata/PartnerMetadataOrchestratorTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/metadata/PartnerMetadataOrchestratorTest.groovy @@ -217,7 +217,7 @@ class PartnerMetadataOrchestratorTest extends Specification { def "getMetadata retrieves metadata successfully"() { given: - String receivedSubmissionId = "receivedSubmissionId" + def receivedSubmissionId = "receivedSubmissionId" def metadata = new PartnerMetadata(receivedSubmissionId, "sentSubmissionId", "sender", "receiver", Instant.now(), "hash") when: @@ -229,6 +229,20 @@ class PartnerMetadataOrchestratorTest extends Specification { 1 * mockPartnerMetadataStorage.readMetadata(receivedSubmissionId) >> Optional.of(metadata) } + def "getMetadata retrieves metadata successfully when receiver is present and sentSubmissionId is missing"() { + given: + def receivedSubmissionId = "receivedSubmissionId" + def metadata = new PartnerMetadata(receivedSubmissionId, null, "sender", "receiver", Instant.now(), "hash") + + when: + def result = PartnerMetadataOrchestrator.getInstance().getMetadata(receivedSubmissionId) + + then: + result.isPresent() + result.get() == metadata + 1 * mockPartnerMetadataStorage.readMetadata(receivedSubmissionId) >> Optional.of(metadata) + } + def "getMetadata gets receiver if missing from metadata"() { given: def receivedSubmissionId = "receivedSubmissionId" @@ -260,13 +274,13 @@ class PartnerMetadataOrchestratorTest extends Specification { def "getReceiverName returns correct receiver name from valid JSON response"() { given: - String validJson = "{\"destinations\": [{\"organization_id\": \"org_id\", \"service\": \"service_name\"}]}" + def validJson = "{\"destinations\": [{\"organization_id\": \"org_id\", \"service\": \"service_name\"}]}" TestApplicationContext.register(Formatter, Jackson.getInstance()) TestApplicationContext.injectRegisteredImplementations() when: - String receiverName = PartnerMetadataOrchestrator.getInstance().getReceiverName(validJson) + def receiverName = PartnerMetadataOrchestrator.getInstance().getReceiverName(validJson) then: receiverName == "org_id.service_name" @@ -278,42 +292,43 @@ class PartnerMetadataOrchestratorTest extends Specification { TestApplicationContext.injectRegisteredImplementations() when: - String invalidJson = "invalid JSON" + def invalidJson = "invalid JSON" PartnerMetadataOrchestrator.getInstance().getReceiverName(invalidJson) then: thrown(FormatterProcessingException) when: - String emptyJson = "{}" + def emptyJson = "{}" PartnerMetadataOrchestrator.getInstance().getReceiverName(emptyJson) then: thrown(FormatterProcessingException) when: - String jsonWithoutDestinations = "{\"someotherkey\": \"value\"}" + def jsonWithoutDestinations = "{\"someotherkey\": \"value\"}" PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutDestinations) then: thrown(FormatterProcessingException) when: - String jsonWithEmptyDestinations = "{\"destinations\": []}" + + def jsonWithEmptyDestinations = "{\"destinations\": []}" def receiverName = PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithEmptyDestinations) then: receiverName == null when: - String jsonWithoutOrgId = "{\"destinations\":[{\"service\":\"service\"}]}" + def jsonWithoutOrgId = "{\"destinations\":[{\"service\":\"service\"}]}" PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutOrgId) then: thrown(FormatterProcessingException) when: - String jsonWithoutService = "{\"destinations\":[{\"organization_id\":\"org_id\"}]}" + def jsonWithoutService = "{\"destinations\":[{\"organization_id\":\"org_id\"}]}" PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutService) then: diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUsecaseTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUsecaseTest.groovy index 6dd7bd174..b18f0437c 100644 --- a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUsecaseTest.groovy +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/orders/SendOrderUsecaseTest.groovy @@ -121,4 +121,19 @@ class SendOrderUsecaseTest extends Specification { 1 * mockLogger.logError(_, _) noExceptionThrown() } + + def "convertAndSend logs event when submissionId is null"() { + given: + def mockOrder = Mock(Order) + TestApplicationContext.injectRegisteredImplementations() + + mockSender.sendOrder(_) >> Optional.empty() + + when: + SendOrderUseCase.getInstance().convertAndSend(mockOrder, "receivedId") + + then: + 1 * mockLogger.logWarning(_) + 0 * mockOrchestrator.updateMetadataForSentOrder(_ as String, _ as String) + } } diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/database/DatabasePartnerMetadataStorageTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/database/DatabasePartnerMetadataStorageTest.groovy new file mode 100644 index 000000000..61aa37d7e --- /dev/null +++ b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/database/DatabasePartnerMetadataStorageTest.groovy @@ -0,0 +1,108 @@ +package gov.hhs.cdc.trustedintermediary.external.database + +import gov.hhs.cdc.trustedintermediary.context.TestApplicationContext +import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadata +import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataException +import gov.hhs.cdc.trustedintermediary.etor.metadata.PartnerMetadataStorage +import gov.hhs.cdc.trustedintermediary.wrappers.DbDao +import spock.lang.Specification + +import java.sql.SQLException +import java.time.Instant + +class DatabasePartnerMetadataStorageTest extends Specification { + + private def mockDao + + def setup() { + TestApplicationContext.reset() + TestApplicationContext.init() + + mockDao = Mock(DbDao) + + TestApplicationContext.register(DbDao, mockDao) + TestApplicationContext.register(PartnerMetadataStorage, DatabasePartnerMetadataStorage.getInstance()) + TestApplicationContext.injectRegisteredImplementations() + } + + def "readMetadata happy path works"() { + given: + def receivedSubmissionId = "receivedSubmissionId" + def mockMetadata = new PartnerMetadata(receivedSubmissionId, "sentSubmissionId", "sender", "receiver", Instant.now(), "hash") + def expectedResult = Optional.of(mockMetadata) + + mockDao.fetchMetadata(_ as String) >> mockMetadata + + when: + def actualResult = DatabasePartnerMetadataStorage.getInstance().readMetadata(receivedSubmissionId) + + then: + actualResult == expectedResult + } + + def "readMetadata unhappy path works"() { + given: + def receivedSubmissionId = "receivedSubmissionId" + mockDao.fetchMetadata(_ as String) >> { throw new SQLException("Something went wrong!") } + + when: + DatabasePartnerMetadataStorage.getInstance().readMetadata(receivedSubmissionId) + + then: + thrown(PartnerMetadataException) + } + + def "saveMetadata happy path works"() { + given: + def receivedSubmissionId = "receivedSubmissionId" + def mockMetadata = new PartnerMetadata( + receivedSubmissionId, + "sentSubmissionId", + "sender", + "receiver", + Instant.now(), + "hash" + ) + + when: + DatabasePartnerMetadataStorage.getInstance().saveMetadata(mockMetadata) + + then: + 1 * mockDao.upsertMetadata( + mockMetadata.receivedSubmissionId(), + mockMetadata.sentSubmissionId(), + mockMetadata.sender(), + mockMetadata.receiver(), + mockMetadata.hash(), + mockMetadata.timeReceived() + ) + } + + def "saveMetadata unhappy path works"() { + given: + def receivedSubmissionId = "receivedSubmissionId" + def mockMetadata = new PartnerMetadata( + receivedSubmissionId, + "sentSubmissionId", + "sender", + "receiver", + Instant.now(), + "hash" + ) + + mockDao.upsertMetadata( + mockMetadata.receivedSubmissionId(), + mockMetadata.sentSubmissionId(), + mockMetadata.sender(), + mockMetadata.receiver(), + mockMetadata.hash(), + mockMetadata.timeReceived() + ) >> { throw new SQLException("Something went wrong!") } + + when: + DatabasePartnerMetadataStorage.getInstance().saveMetadata(mockMetadata) + + then: + thrown(PartnerMetadataException) + } +} diff --git a/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/utils/SyncRetryTaskTest.groovy b/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/utils/SyncRetryTaskTest.groovy index 1355e3736..c540d3e38 100644 --- a/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/utils/SyncRetryTaskTest.groovy +++ b/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/utils/SyncRetryTaskTest.groovy @@ -18,7 +18,7 @@ class SyncRetryTaskTest extends Specification { given: def maxRetries = 3 def waitTime = 10 - Callable mockTask = Mock(Callable) + def mockTask = Mock(Callable) when: def result = SyncRetryTask.getInstance().retry(mockTask, maxRetries, waitTime) @@ -33,7 +33,7 @@ class SyncRetryTaskTest extends Specification { given: def maxRetries = 3 def waitTime = 10 - Callable mockTask = Mock(Callable) + def mockTask = Mock(Callable) when: SyncRetryTask.getInstance().retry(mockTask, maxRetries, waitTime) @@ -43,4 +43,28 @@ class SyncRetryTaskTest extends Specification { def exception = thrown(RetryFailedException) exception.getCause().getClass() == Exception } + + def "should handle thread interruption"() { + given: + def mockCallable = Mock(Callable) + mockCallable.call() >> { throw new Exception("Fail") } + Exception thrown + def syncRetryTask = SyncRetryTask.getInstance() + + when: + def thread = new Thread({ + try { + syncRetryTask.retry(mockCallable, 3, 1000) + } catch (RetryFailedException e) { + thrown = e + } + }) + thread.start() + Thread.sleep(500) + thread.interrupt() + thread.join() + + then: + thrown.cause instanceof InterruptedException + } }