Skip to content

Commit

Permalink
BFD-2720: Fix bug with samhsa matcher class cast in RDA logic (#1812)
Browse files Browse the repository at this point in the history
Fixes a bug caused during the adjustment to use dependency injection in RDA code which was miscasting the response during the SAMHSA check.
lsmitchell authored Jun 29, 2023
1 parent f7d4f2a commit 31a903f
Showing 5 changed files with 156 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -21,8 +21,6 @@
import com.codahale.metrics.MetricRegistry;
import com.google.common.annotations.VisibleForTesting;
import com.newrelic.api.agent.Trace;
import gov.cms.bfd.model.rda.RdaFissClaim;
import gov.cms.bfd.model.rda.RdaMcsClaim;
import gov.cms.bfd.server.war.commons.AbstractResourceProvider;
import gov.cms.bfd.server.war.commons.OffsetLinkBuilder;
import gov.cms.bfd.server.war.commons.OpenAPIContentProvider;
@@ -52,7 +50,6 @@
import org.apache.logging.log4j.util.Strings;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Claim;
import org.hl7.fhir.r4.model.ClaimResponse;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Resource;
@@ -427,7 +424,7 @@ Bundle createBundleFor(

resources.addAll(
entities.stream()
.filter(e -> !bundleOptions.excludeSamhsa || hasNoSamhsaData(e))
.filter(e -> !bundleOptions.excludeSamhsa || samhsaMatcher.hasNoSamhsaData(e))
.map(e -> transformEntity(type, e, bundleOptions.includeTaxNumbers))
.collect(Collectors.toList()));
}
@@ -453,28 +450,6 @@ Bundle createBundleFor(
return bundle;
}

/**
* Determines if there are no samhsa entries in the claim.
*
* @param entity the claim to check
* @return {@code true} if there are no samhsa entries in the claim
*/
@VisibleForTesting
boolean hasNoSamhsaData(Object entity) {
Claim claim;

if (entity instanceof RdaFissClaim) {
claim = (Claim) fissTransformer.transform(entity, false);
} else if (entity instanceof RdaMcsClaim) {
claim = (Claim) mcsTransformer.transform(entity, false);
} else {
throw new IllegalArgumentException(
"Unsupported entity " + entity.getClass().getCanonicalName() + " for samhsa filtering");
}

return !samhsaMatcher.test(claim);
}

/** Helper class for passing bundle result options. */
private static class BundleOptions {

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package gov.cms.bfd.server.war.r4.providers.pac;

import gov.cms.bfd.model.rda.RdaFissClaim;
import gov.cms.bfd.model.rda.RdaMcsClaim;
import gov.cms.bfd.server.war.adapters.CodeableConcept;
import gov.cms.bfd.server.war.adapters.r4.ClaimAdapter;
import gov.cms.bfd.server.war.commons.AbstractSamhsaMatcher;
@@ -21,6 +23,47 @@
@Component
public final class R4ClaimSamhsaMatcher extends AbstractSamhsaMatcher<Claim> {

/** The fiss claim transformer, used for converting resources to check for samhsa data. */
private final FissClaimTransformerV2 fissTransformer;

/** The mcs claim transformer, used for converting resources to check for samhsa data. */
private final McsClaimTransformerV2 mcsTransformer;

/**
* Instantiates a new samhsa matcher.
*
* <p>Resources should be instantiated by Spring, so this should only be directly called by tests.
*
* @param fissClaimTransformer the fiss claim transformer
* @param mcsClaimTransformer the mcs claim transformer
*/
public R4ClaimSamhsaMatcher(
FissClaimTransformerV2 fissClaimTransformer, McsClaimTransformerV2 mcsClaimTransformer) {
this.mcsTransformer = mcsClaimTransformer;
this.fissTransformer = fissClaimTransformer;
}

/**
* Determines if there are no samhsa entries in the claim.
*
* @param entity the claim to check
* @return {@code true} if there are no samhsa entries in the claim
*/
public boolean hasNoSamhsaData(Object entity) {
Claim claim;

if (entity instanceof RdaFissClaim) {
claim = fissTransformer.transform(entity, false);
} else if (entity instanceof RdaMcsClaim) {
claim = mcsTransformer.transform(entity, false);
} else {
throw new IllegalArgumentException(
"Unsupported entity " + entity.getClass().getCanonicalName() + " for samhsa filtering");
}

return !test(claim);
}

/** {@inheritDoc} */
@Override
public boolean test(Claim claim) {
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package gov.cms.bfd.server.war.r4.providers.pac;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.param.DateParam;
@@ -115,6 +117,33 @@ void shouldGetCorrectClaimResponseResourcesByMbiHash() {
AssertUtils.assertJsonEquals(expected, actual, ignorePatterns);
}

/**
* Tests to see if the correct response is given when a search is done for {@link ClaimResponse}s
* using given mbi and excludeSAMHSA=true, since this does an extra check for samhsa data.
*/
@Test
void shouldGetClaimResponseResourcesByMbiHashWithExcludeSamhsaTrue() {
IGenericClient fhirClient = ServerTestUtils.get().createFhirClientV2();

Bundle claimResult =
fhirClient
.search()
.forResource(ClaimResponse.class)
.where(
Map.of(
"mbi",
Collections.singletonList(new ReferenceParam(RDATestUtils.MBI_OLD_HASH)),
"service-date",
Arrays.asList(new DateParam("gt1970-07-18"), new DateParam("lt1970-07-25")),
"excludeSAMHSA",
Collections.singletonList(new ReferenceParam("true"))))
.returnBundle(Bundle.class)
.execute();

// Ensure we got a result and not an exception
assertNotNull(claimResult);
}

/**
* Tests to see if the correct paginated response is given when a search is done for {@link
* ClaimResponse}s using given mbi and service-date range. In this test case the query finds the
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package gov.cms.bfd.server.war.r4.providers.pac;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import gov.cms.bfd.model.rda.RdaFissClaim;
import gov.cms.bfd.model.rda.RdaMcsClaim;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r4.model.Claim;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

/** Tests the methods of the {@link R4ClaimSamhsaMatcher}. */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class R4ClaimSamhsaMatcherTest {

/** The class under test. */
private R4ClaimSamhsaMatcher samhsaMatcher;

/** The fiss claim transformer. */
@Mock private FissClaimTransformerV2 mockFissTransformer;

/** The mock mcs claim transformer. */
@Mock private McsClaimTransformerV2 mockMcsTransformer;

/** The mock claim returned by the transformers. */
@Mock private Claim mockClaim;

/** Sets up the class under test and dependencies. */
@BeforeEach
public void setup() {
samhsaMatcher = new R4ClaimSamhsaMatcher(mockFissTransformer, mockMcsTransformer);
when(mockFissTransformer.transform(any(), anyBoolean())).thenReturn(mockClaim);
when(mockMcsTransformer.transform(any(), anyBoolean())).thenReturn(mockClaim);
List<Claim.ProcedureComponent> procedureComponentList = new ArrayList<>();
when(mockClaim.getProcedure()).thenReturn(procedureComponentList);
}

/**
* Tests that the samhsa checker is invoked and returns true when a mcs claim with no data is
* passed, as the matches should have nothing to match as a positive samhsa result.
*/
@Test
public void testHasNoSamhsaDataWhenMcsClaimResponseWithNoDataExpectTrue() {

RdaMcsClaim mcsClaim = mock(RdaMcsClaim.class);

boolean hasNoSamhsa = samhsaMatcher.hasNoSamhsaData(mcsClaim);

assertTrue(hasNoSamhsa);
}

/**
* Tests that the samhsa checker is invoked and returns true when a fiss claim with no data is
* passed, as the matches should have nothing to match as a positive samhsa result.
*/
@Test
public void testHasNoSamhsaDataWhenFissClaimResponseWithNoDataExpectTrue() {

RdaFissClaim fissClaim = mock(RdaFissClaim.class);

boolean hasNoSamhsa = samhsaMatcher.hasNoSamhsaData(fissClaim);

assertTrue(hasNoSamhsa);
}
}
Original file line number Diff line number Diff line change
@@ -188,10 +188,12 @@ public void fissTest(

FissClaimTransformerV2 fissClaimTransformerV2 =
new FissClaimTransformerV2(new MetricRegistry());
McsClaimTransformerV2 mcsClaimTransformerV2 = new McsClaimTransformerV2(new MetricRegistry());

Claim claim = fissClaimTransformerV2.transform(entity, true);

R4ClaimSamhsaMatcher matcher = new R4ClaimSamhsaMatcher();
R4ClaimSamhsaMatcher matcher =
new R4ClaimSamhsaMatcher(fissClaimTransformerV2, mcsClaimTransformerV2);

assertEquals(expectedResult, matcher.test(claim), testName + " " + errorMessagePostFix);
}
@@ -283,11 +285,14 @@ public void mcsTest(

entity.setDetails(procedures);

FissClaimTransformerV2 fissClaimTransformerV2 =
new FissClaimTransformerV2(new MetricRegistry());
McsClaimTransformerV2 mcsClaimTransformerV2 = new McsClaimTransformerV2(new MetricRegistry());

Claim claim = mcsClaimTransformerV2.transform(entity, true);

R4ClaimSamhsaMatcher matcher = new R4ClaimSamhsaMatcher();
R4ClaimSamhsaMatcher matcher =
new R4ClaimSamhsaMatcher(fissClaimTransformerV2, mcsClaimTransformerV2);

assertEquals(expectedResult, matcher.test(claim), testName + " " + errorMessagePostFix);
}

0 comments on commit 31a903f

Please sign in to comment.