From 115126109a33cdf66167a300a7c5cd66b4c1abce Mon Sep 17 00:00:00 2001 From: Brick Green Date: Wed, 8 Dec 2021 13:33:25 -0600 Subject: [PATCH 01/20] added null check on originState --- .../src/main/kotlin/serializers/Hl7Serializer.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/prime-router/src/main/kotlin/serializers/Hl7Serializer.kt b/prime-router/src/main/kotlin/serializers/Hl7Serializer.kt index c36720b10ee..78f3a0c6b02 100644 --- a/prime-router/src/main/kotlin/serializers/Hl7Serializer.kt +++ b/prime-router/src/main/kotlin/serializers/Hl7Serializer.kt @@ -580,18 +580,20 @@ class Hl7Serializer( val pathSpecTestingState = formPathSpec(testingStateField) var originState = terser.get(pathSpecTestingState) - if (originState.isEmpty()) { + if (originState.isNullOrEmpty()) { val orderingStateField = "ORC-24-4" val pathSpecOrderingState = formPathSpec(orderingStateField) originState = terser.get(pathSpecOrderingState) } - val stateCode = report.destination?.let { settings.findOrganization(it.organizationName)?.stateCode } + if (!originState.isNullOrEmpty()) { + val stateCode = report.destination?.let { settings.findOrganization(it.organizationName)?.stateCode } - if (!originState.equals(stateCode)) { - val sendingFacility = "MSH-4-2" - val pathSpecSendingFacility = formPathSpec(sendingFacility) - terser.set(pathSpecSendingFacility, hl7Config?.cliaForOutOfStateTesting) + if (!originState.equals(stateCode)) { + val sendingFacility = "MSH-4-2" + val pathSpecSendingFacility = formPathSpec(sendingFacility) + terser.set(pathSpecSendingFacility, hl7Config?.cliaForOutOfStateTesting) + } } } From f29c6ddaa2582264ee84a2e8a0b4eaa181799127 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Wed, 8 Dec 2021 14:20:53 -0600 Subject: [PATCH 02/20] add unit test for cliaForOutOFStateTesting --- .../Hl7SerializerIntegrationTests.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 1187d34f14a..626adae28a2 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -452,6 +452,36 @@ NTE|1|L|This is a final comment|RE""" assertThat(result.report).isNull() } + @Test + fun `test cliaForOutOfStateTesting`() { + // arrange + val mcf = CanonicalModelClassFactory("2.5.1") + context.modelClassFactory = mcf + val parser = context.pipeParser + // act + val reg = "[\r\n]".toRegex() + + // val csv = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility/nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,,,,,,,,,,,,,,,,93307,kern,,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,,,,,,,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + val csv = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,CA,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,CA,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + + // SenderID is set to "fake" in this CSV + val csvContent = ByteArrayInputStream(csv.toByteArray()) + val schema = "direct/direct-covid-19" + + val hl7Config = createConfig(cliaForOutOfStateTesting = "10DfakeCL") + val receiver = Receiver("test", "ca-dph", "covid-19", translation = hl7Config) + + val testReport = csvSerializer.readExternal(schema, csvContent, listOf(TestSource), receiver).report ?: fail() + val output = serializer.createMessage(testReport, 0) + + val cleanedMessage = reg.replace(output, "\r") + val hapiMsg = parser.parse(cleanedMessage) + val terser = Terser(hapiMsg) + val cliaTersed = terser.get("/MSH-4-2") + + assertThat(cliaTersed).isNotEqualTo("10DfakeCL") + } + @Test fun `test cliaForSender`() { // arrange From 16ee78458138f93554d24b54b2caeba250a612bc Mon Sep 17 00:00:00 2001 From: Brick Green Date: Thu, 9 Dec 2021 10:54:42 -0600 Subject: [PATCH 03/20] addd tests for missing state, only provider state, and only ordering state --- .../Hl7SerializerIntegrationTests.kt | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 626adae28a2..ec078171ffc 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -461,25 +461,62 @@ NTE|1|L|This is a final comment|RE""" // act val reg = "[\r\n]".toRegex() - // val csv = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility/nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,,,,,,,,,,,,,,,,93307,kern,,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,,,,,,,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length - val csv = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,CA,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,CA,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + val hl7Config = createConfig(cliaForOutOfStateTesting = "10DfakeCL") + val receiver = Receiver("test", "ca-dph", "covid-19", translation = hl7Config) + val schema = "direct/direct-covid-19" + + val csvBlankState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length // SenderID is set to "fake" in this CSV - val csvContent = ByteArrayInputStream(csv.toByteArray()) - val schema = "direct/direct-covid-19" + val csvContentBlankState = ByteArrayInputStream(csvBlankState.toByteArray()) + val testReportBlankState = csvSerializer + .readExternal(schema, csvContentBlankState, listOf(TestSource), receiver) + .report ?: fail() - val hl7Config = createConfig(cliaForOutOfStateTesting = "10DfakeCL") - val receiver = Receiver("test", "ca-dph", "covid-19", translation = hl7Config) + val outputBlankState = serializer.createMessage(testReportBlankState, 0) - val testReport = csvSerializer.readExternal(schema, csvContent, listOf(TestSource), receiver).report ?: fail() - val output = serializer.createMessage(testReport, 0) + val cleanedMessageBlankState = reg.replace(outputBlankState, "\r") + val hapiMsgBlankState = parser.parse(cleanedMessageBlankState) + val terserBlankState = Terser(hapiMsgBlankState) + val cliaTersedBlankState = terserBlankState.get("/MSH-4-2") - val cleanedMessage = reg.replace(output, "\r") - val hapiMsg = parser.parse(cleanedMessage) - val terser = Terser(hapiMsg) - val cliaTersed = terser.get("/MSH-4-2") + assertThat(cliaTersedBlankState).isNotEqualTo("10DfakeCL") + + val csvCompleteProviderState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + + // SenderID is set to "fake" in this CSV + val csvContentProviderState = ByteArrayInputStream(csvCompleteProviderState.toByteArray()) + + val testReportProviderState = csvSerializer + .readExternal(schema, csvContentProviderState, listOf(TestSource), receiver) + .report ?: fail() + + val outputProviderState = serializer.createMessage(testReportProviderState, 0) + + val cleanedMessageProviderState = reg.replace(outputProviderState, "\r") + val hapiMsgProviderState = parser.parse(cleanedMessageProviderState) + val terserProviderState = Terser(hapiMsgProviderState) + val cliaTersedProviderState = terserProviderState.get("/MSH-4-2") + + assertThat(cliaTersedProviderState).isEqualTo("10DfakeCL") + + val csvCompleteFacilityState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + + // SenderID is set to "fake" in this CSV + val csvContentFacilityState = ByteArrayInputStream(csvCompleteFacilityState.toByteArray()) + + val testReportFacilityState = csvSerializer + .readExternal(schema, csvContentFacilityState, listOf(TestSource), receiver) + .report ?: fail() + + val outputFacilityState = serializer.createMessage(testReportFacilityState, 0) + + val cleanedMessageFacilityState = reg.replace(outputFacilityState, "\r") + val hapiMsgFacilityState = parser.parse(cleanedMessageFacilityState) + val terserFacilityState = Terser(hapiMsgFacilityState) + val cliaTersedFacilityState = terserFacilityState.get("/MSH-4-2") - assertThat(cliaTersed).isNotEqualTo("10DfakeCL") + assertThat(cliaTersedFacilityState).isEqualTo("10DfakeCL") } @Test From 20532f16bddb955c58223c9831edccd768e08df2 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Thu, 9 Dec 2021 16:08:39 -0600 Subject: [PATCH 04/20] adjusted the strings to conform with ktlint length --- .../Hl7SerializerIntegrationTests.kt | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index ec078171ffc..72fd30ff888 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File +import java.lang.StringBuilder import java.nio.charset.StandardCharsets import kotlin.test.fail @@ -464,11 +465,34 @@ NTE|1|L|This is a final comment|RE""" val hl7Config = createConfig(cliaForOutOfStateTesting = "10DfakeCL") val receiver = Receiver("test", "ca-dph", "covid-19", translation = hl7Config) val schema = "direct/direct-covid-19" - - val csvBlankState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + val csvHeader = StringBuilder() + csvHeader.append("senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,") + .append("testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,") + .append("deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,") + .append("patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,") + .append("orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,") + .append("performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,") + .append("performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,") + .append("orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,") + .append("orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,") + .append("patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,") + .append("patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,") + .append("orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,") + .append("previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,") + .append("hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\n") + + val csvBlankState = StringBuilder() + csvBlankState.append(csvHeader) + .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") + .append("Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") + .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,") + .append("45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") + .append("9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,") + .append("93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,") + .append(",9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") // SenderID is set to "fake" in this CSV - val csvContentBlankState = ByteArrayInputStream(csvBlankState.toByteArray()) + val csvContentBlankState = ByteArrayInputStream(csvBlankState.toString().toByteArray()) val testReportBlankState = csvSerializer .readExternal(schema, csvContentBlankState, listOf(TestSource), receiver) .report ?: fail() @@ -482,10 +506,18 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedBlankState).isNotEqualTo("10DfakeCL") - val csvCompleteProviderState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + val csvCompleteProviderState = StringBuilder() + csvCompleteProviderState.append(csvHeader) + .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") + .append("Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") + .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,") + .append("yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") + .append("9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,") + .append("93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,") + .append(",9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") // SenderID is set to "fake" in this CSV - val csvContentProviderState = ByteArrayInputStream(csvCompleteProviderState.toByteArray()) + val csvContentProviderState = ByteArrayInputStream(csvCompleteProviderState.toString().toByteArray()) val testReportProviderState = csvSerializer .readExternal(schema, csvContentProviderState, listOf(TestSource), receiver) @@ -500,10 +532,18 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedProviderState).isEqualTo("10DfakeCL") - val csvCompleteFacilityState = "senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\nfake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880" // ktlint-disable max-line-length + val csvCompleteFacilityState = StringBuilder() + csvCompleteFacilityState.append(csvHeader) + .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") + .append("Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") + .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,") + .append("yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") + .append("9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,") + .append("Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,") + .append("9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") // SenderID is set to "fake" in this CSV - val csvContentFacilityState = ByteArrayInputStream(csvCompleteFacilityState.toByteArray()) + val csvContentFacilityState = ByteArrayInputStream(csvCompleteFacilityState.toString().toByteArray()) val testReportFacilityState = csvSerializer .readExternal(schema, csvContentFacilityState, listOf(TestSource), receiver) From c481e14889c332fb04c8306c19a5425052b61ad6 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Thu, 9 Dec 2021 18:58:54 -0600 Subject: [PATCH 05/20] changed away from sting builder --- .../Hl7SerializerIntegrationTests.kt | 79 +++++++++---------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 72fd30ff888..8a205a262b8 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -465,31 +465,28 @@ NTE|1|L|This is a final comment|RE""" val hl7Config = createConfig(cliaForOutOfStateTesting = "10DfakeCL") val receiver = Receiver("test", "ca-dph", "covid-19", translation = hl7Config) val schema = "direct/direct-covid-19" - val csvHeader = StringBuilder() - csvHeader.append("senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed,") - .append("testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier,") - .append("deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText,") - .append("patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi,") - .append("orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName,") - .append("performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState,") - .append("performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName,") - .append("orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip,") - .append("orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst,") - .append("patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState,") - .append("patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity,") - .append("orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate,") - .append("previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized,") - .append("hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\n") - - val csvBlankState = StringBuilder() - csvBlankState.append(csvHeader) - .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") - .append("Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") - .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,") - .append("45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") - .append("9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,") - .append("93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,") - .append(",9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") + val csvHeader = """senderId,testOrdered,testName,testCodingSystem,testResult,testResultText,testPerformed, + testResultCodingSystem,testResultDate,testReportDate,testOrderedDate,specimenCollectedDate,deviceIdentifier, + deviceName,specimenId,serialNumber,patientAge,patientAgeUnits,patientDob,patientRace,patientRaceText, + patientEthnicity,patientEthnicityText,patientSex,patientZip,patientCounty,orderingProviderNpi, + orderingProviderLname,orderingProviderFname,orderingProviderZip,performingFacility,performingFacilityName, + performingFacilityStreet,performingFacilityStreet2,performingFacilityCity,performingFacilityState, + performingFacilityZip,performingFacilityCounty,performingFacilityPhone,orderingFacilityName, + orderingFacilityStreet,orderingFacilityStreet2,orderingFacilityCity,orderingFacilityState,orderingFacilityZip, + orderingFacilityCounty,orderingFacilityPhone,specimenSource,patientNameLast,patientNameFirst, + patientNameMiddle,patientUniqueId,patientHomeAddress,patientHomeAddress2,patientCity,patientState, + patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity, + orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate, + previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized, + hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\n""" + + val csvBlankState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, + BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42, + 45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, + 9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,, + 93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107, + ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" // SenderID is set to "fake" in this CSV val csvContentBlankState = ByteArrayInputStream(csvBlankState.toString().toByteArray()) @@ -506,15 +503,13 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedBlankState).isNotEqualTo("10DfakeCL") - val csvCompleteProviderState = StringBuilder() - csvCompleteProviderState.append(csvHeader) - .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") - .append("Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") - .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,") - .append("yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") - .append("9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,,") - .append("93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,") - .append(",9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") + val csvCompleteProviderState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, + BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45, + yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, + 9902 Brimhall rd ste 100,,Bakersfield,TX,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,, + 93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107, + ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" // SenderID is set to "fake" in this CSV val csvContentProviderState = ByteArrayInputStream(csvCompleteProviderState.toString().toByteArray()) @@ -532,15 +527,13 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedProviderState).isEqualTo("10DfakeCL") - val csvCompleteFacilityState = StringBuilder() - csvCompleteFacilityState.append(csvHeader) - .append("fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000,") - .append("Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821,") - .append("BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45,") - .append("yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy,") - .append("9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312,") - .append("Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661,") - .append("9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880") + val csvCompleteFacilityState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, + BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45, + yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, + 9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,TX,93312, + Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107,661, + 9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" // SenderID is set to "fake" in this CSV val csvContentFacilityState = ByteArrayInputStream(csvCompleteFacilityState.toString().toByteArray()) From 12e043c7bcaca9fd55655e9277555e8744c24dd0 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Thu, 9 Dec 2021 20:48:32 -0600 Subject: [PATCH 06/20] fix errror with multiline string --- .../Hl7SerializerIntegrationTests.kt | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 8a205a262b8..8fd9f03a98d 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File -import java.lang.StringBuilder import java.nio.charset.StandardCharsets import kotlin.test.fail @@ -478,18 +477,22 @@ NTE|1|L|This is a final comment|RE""" patientPhone,patientPhoneArea,orderingProviderAddress,orderingProviderAddress2,orderingProviderCity, orderingProviderState,orderingProviderPhone,orderingProviderPhoneArea,firstTest,previousTestType,previousTestDate, previousTestResult,correctedTestId,healthcareEmployee,healthcareEmployeeType,symptomatic,symptomsList,hospitalized, - hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility\n""" + hospitalizedCode,symptomsIcu,congregateResident,congregateResidentType,pregnant,pregnantText,patientEmail,reportingFacility""" - val csvBlankState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + val csvBlankState = """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42, 45,yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, 9902 Brimhall rd ste 100,,Bakersfield,,93312,Kern County,+16618297861,Inovia Pharmacy,9902 Brimhall rd ste 100,,Bakersfield,, 93312,Kern County,+16618297861,445297001,Tapia,Jose,,e553c462-6bad-4e42-ab1e-0879b797aa31,1211 Dawn st,,Bakersfield,CA,+16614933107, - ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" + ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661, + UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" - // SenderID is set to "fake" in this CSV - val csvContentBlankState = ByteArrayInputStream(csvBlankState.toString().toByteArray()) + val test = csvHeader.replace("\n ", "") + .plus("\n") + .plus(csvBlankState.replace("\n ", "")) + + val csvContentBlankState = ByteArrayInputStream(test.toByteArray()) val testReportBlankState = csvSerializer .readExternal(schema, csvContentBlankState, listOf(TestSource), receiver) .report ?: fail() @@ -503,7 +506,7 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedBlankState).isNotEqualTo("10DfakeCL") - val csvCompleteProviderState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + val csvCompleteProviderState = """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45, yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, @@ -512,7 +515,12 @@ NTE|1|L|This is a final comment|RE""" ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,CA,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" // SenderID is set to "fake" in this CSV - val csvContentProviderState = ByteArrayInputStream(csvCompleteProviderState.toString().toByteArray()) + val csvContentProviderState = ByteArrayInputStream( + csvHeader.replace("\n ", "") + .plus("\n") + .plus(csvCompleteProviderState.replace("\n ", "")) + .toByteArray() + ) val testReportProviderState = csvSerializer .readExternal(schema, csvContentProviderState, listOf(TestSource), receiver) @@ -527,7 +535,7 @@ NTE|1|L|This is a final comment|RE""" assertThat(cliaTersedProviderState).isEqualTo("10DfakeCL") - val csvCompleteFacilityState = csvHeader + """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, + val csvCompleteFacilityState = """fake,94531-1,SARS coronavirus 2 RNA panel - Respiratory specimen by NAA with probe detection,LN,260415000, Not Detected,94558-4,SCT,202110062022-0400,202110062022-0400,20211007,20211007,00382902560821, BD Veritor System for Rapid Detection of SARS-CoV-2*,4efd9df8-9424-4e50-b168-f3aa894bfa42,4efd9df8-9424-4e50-b168-f3aa894bfa42,45, yr,1975-10-10,2106-3,White,2135-2,Hispanic or Latino,M,93307,Kern County,1760085880,,,93312,05D2191150,Inovia Pharmacy, @@ -536,7 +544,12 @@ NTE|1|L|This is a final comment|RE""" 9902 BRIMHALL RD STE 100,,BAKERSFIELD,TX,+16618297861,661,UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" // SenderID is set to "fake" in this CSV - val csvContentFacilityState = ByteArrayInputStream(csvCompleteFacilityState.toString().toByteArray()) + val csvContentFacilityState = ByteArrayInputStream( + csvHeader.replace("\n ", "") + .plus("\n") + .plus(csvCompleteFacilityState.replace("\n ", "")) + .toByteArray() + ) val testReportFacilityState = csvSerializer .readExternal(schema, csvContentFacilityState, listOf(TestSource), receiver) From 4ca4c784602f40083c74d7518eeabc12c1600464 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 14:14:21 +0000 Subject: [PATCH 07/20] Bump org.flywaydb.flyway from 8.0.4 to 8.2.0 in /prime-router (#3261) Bumps org.flywaydb.flyway from 8.0.4 to 8.2.0. --- updated-dependencies: - dependency-name: org.flywaydb.flyway dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maurice Reeves <74194189+MauriceReeves-usds@users.noreply.github.com> --- prime-router/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index ef6567d34c2..7c3883ab409 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -28,7 +28,7 @@ import java.util.Properties plugins { kotlin("jvm") version "1.6.0" - id("org.flywaydb.flyway") version "8.0.4" + id("org.flywaydb.flyway") version "8.2.0" id("nu.studer.jooq") version "6.0.1" id("com.github.johnrengelman.shadow") version "7.1.0" id("com.microsoft.azure.azurefunctions") version "1.8.1" From 8d8b0567646dbb173ac04cd11997f4e46af2966d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 14:32:30 +0000 Subject: [PATCH 08/20] Bump ktorVersion from 1.6.4 to 1.6.7 in /prime-router (#3353) Bumps `ktorVersion` from 1.6.4 to 1.6.7. Updates `ktor-client-core` from 1.6.4 to 1.6.7 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/commits) Updates `ktor-client-cio` from 1.6.4 to 1.6.7 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/commits) Updates `ktor-client-apache` from 1.6.4 to 1.6.7 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/commits) Updates `ktor-client-logging` from 1.6.4 to 1.6.7 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/commits) Updates `ktor-client-mock` from 1.6.4 to 1.6.7 - [Release notes](https://github.com/ktorio/ktor/releases) - [Changelog](https://github.com/ktorio/ktor/blob/main/CHANGELOG.md) - [Commits](https://github.com/ktorio/ktor/commits) --- updated-dependencies: - dependency-name: io.ktor:ktor-client-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-cio dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-apache dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-logging dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.ktor:ktor-client-mock dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maurice Reeves <74194189+MauriceReeves-usds@users.noreply.github.com> --- prime-router/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index 7c3883ab409..7eb6c798d25 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -90,7 +90,7 @@ fun addVaultValuesToEnv(env: MutableMap) { defaultTasks("package") -val ktorVersion = "1.6.4" +val ktorVersion = "1.6.7" val kotlinVersion = "1.6.0" jacoco.toolVersion = "0.8.7" From 380505cf776544878deb38221951788c4a1da464 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 14:58:28 +0000 Subject: [PATCH 09/20] Bump azure-core from 1.22.0 to 1.23.1 in /prime-router (#3352) Bumps [azure-core](https://github.com/Azure/azure-sdk-for-java) from 1.22.0 to 1.23.1. - [Release notes](https://github.com/Azure/azure-sdk-for-java/releases) - [Commits](https://github.com/Azure/azure-sdk-for-java/compare/azure-core_1.22.0...azure-core_1.23.1) --- updated-dependencies: - dependency-name: com.azure:azure-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maurice Reeves <74194189+MauriceReeves-usds@users.noreply.github.com> --- prime-router/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index 7eb6c798d25..b5e1cbf5e91 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -574,7 +574,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2") implementation("com.microsoft.azure.functions:azure-functions-java-library:1.4.2") - implementation("com.azure:azure-core:1.22.0") + implementation("com.azure:azure-core:1.23.1") implementation("com.azure:azure-core-http-netty:1.11.2") implementation("com.azure:azure-storage-blob:12.14.1") { exclude(group = "com.azure", module = "azure-core") From bf21907284f34bba7669a706770d7d3949f72428 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 10:00:55 -0500 Subject: [PATCH 10/20] Bump junit-jupiter-api from 5.8.1 to 5.8.2 in /prime-router (#3263) Bumps [junit-jupiter-api](https://github.com/junit-team/junit5) from 5.8.1 to 5.8.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rick Hawes Co-authored-by: Maurice Reeves <74194189+MauriceReeves-usds@users.noreply.github.com> --- prime-router/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index b5e1cbf5e91..29c6d8cd10f 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -660,7 +660,7 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2") testImplementation("com.github.KennethWussmann:mock-fuel:1.3.0") testImplementation("io.mockk:mockk:1.12.1") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2") testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") testImplementation("io.ktor:ktor-client-mock:$ktorVersion") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2") From e72a8b1b7ce6d0a939f3a0f58f9efad8f7050f0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 10:01:06 -0500 Subject: [PATCH 11/20] Bump thymeleaf from 3.0.12.RELEASE to 3.0.14.RELEASE in /prime-router (#3354) Bumps [thymeleaf](https://github.com/thymeleaf/thymeleaf) from 3.0.12.RELEASE to 3.0.14.RELEASE. - [Release notes](https://github.com/thymeleaf/thymeleaf/releases) - [Changelog](https://github.com/thymeleaf/thymeleaf/blob/3.0-master/ChangeLog.txt) - [Commits](https://github.com/thymeleaf/thymeleaf/compare/thymeleaf-3.0.12.RELEASE...thymeleaf-3.0.14.RELEASE) --- updated-dependencies: - dependency-name: org.thymeleaf:thymeleaf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maurice Reeves <74194189+MauriceReeves-usds@users.noreply.github.com> --- prime-router/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index 29c6d8cd10f..6f84035063f 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -605,7 +605,7 @@ dependencies { implementation("ca.uhn.hapi:hapi-base:2.3") implementation("ca.uhn.hapi:hapi-structures-v251:2.3") implementation("com.googlecode.libphonenumber:libphonenumber:8.12.38") - implementation("org.thymeleaf:thymeleaf:3.0.12.RELEASE") + implementation("org.thymeleaf:thymeleaf:3.0.14.RELEASE") implementation("com.sendgrid:sendgrid-java:4.8.0") implementation("com.okta.jwt:okta-jwt-verifier:0.5.1") implementation("com.github.kittinunf.fuel:fuel:2.3.1") { From f18d6f79fb49e95cedb84ec0dcc040b804e90e53 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Fri, 10 Dec 2021 09:48:31 -0600 Subject: [PATCH 12/20] consolidated variables --- .../serializers/Hl7SerializerIntegrationTests.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 8fd9f03a98d..5c6b4c8b214 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -488,11 +488,13 @@ NTE|1|L|This is a final comment|RE""" ,9902 BRIMHALL RD STE 100,,BAKERSFIELD,,+16618297861,661, UNK,,,,,,,UNK,,NO,,NO,NO,,261665006,UNK,,1760085880""" - val test = csvHeader.replace("\n ", "") - .plus("\n") - .plus(csvBlankState.replace("\n ", "")) + val csvContentBlankState = ByteArrayInputStream( + csvHeader.replace("\n ", "") + .plus("\n") + .plus(csvBlankState.replace("\n ", "")) + .toByteArray() + ) - val csvContentBlankState = ByteArrayInputStream(test.toByteArray()) val testReportBlankState = csvSerializer .readExternal(schema, csvContentBlankState, listOf(TestSource), receiver) .report ?: fail() @@ -516,9 +518,9 @@ NTE|1|L|This is a final comment|RE""" // SenderID is set to "fake" in this CSV val csvContentProviderState = ByteArrayInputStream( - csvHeader.replace("\n ", "") + csvHeader.replace("\n", "").trimIndent() .plus("\n") - .plus(csvCompleteProviderState.replace("\n ", "")) + .plus(csvCompleteProviderState.replace("\n", "").trimIndent()) .toByteArray() ) From fa454a1b43b7d3dc70aeed08dbcff4511a664d00 Mon Sep 17 00:00:00 2001 From: Brick Green Date: Fri, 10 Dec 2021 09:50:44 -0600 Subject: [PATCH 13/20] removed trimIndent --- .../kotlin/serializers/Hl7SerializerIntegrationTests.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt index 5c6b4c8b214..bd595f7b83c 100644 --- a/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt +++ b/prime-router/src/testIntegration/kotlin/serializers/Hl7SerializerIntegrationTests.kt @@ -518,9 +518,9 @@ NTE|1|L|This is a final comment|RE""" // SenderID is set to "fake" in this CSV val csvContentProviderState = ByteArrayInputStream( - csvHeader.replace("\n", "").trimIndent() + csvHeader.replace("\n ", "") .plus("\n") - .plus(csvCompleteProviderState.replace("\n", "").trimIndent()) + .plus(csvCompleteProviderState.replace("\n ", "")) .toByteArray() ) From 42bd1ae13c044eab1f63b1589941b8438943d8f5 Mon Sep 17 00:00:00 2001 From: TomNUSDS <74203452+TomNUSDS@users.noreply.github.com> Date: Fri, 10 Dec 2021 08:27:11 -0800 Subject: [PATCH 14/20] Fix unit tests (#3389) - Fix all broken unit tests --- frontend-react/package.json | 4 +- frontend-react/src/components/Title.test.tsx | 16 ++ frontend-react/src/content/content.json | 17 +- frontend-react/src/pages/home/Home.test.tsx | 24 +-- frontend-react/src/pages/home/Home.tsx | 4 +- .../src/pages/tos-sign/SuccessPage.test.tsx | 18 +- .../src/pages/tos-sign/SuccessPage.tsx | 4 +- .../tos-sign/TermsOfServiceForm.test.tsx | 154 +++++++++--------- .../src/pages/tos-sign/TermsOfServiceForm.tsx | 9 + frontend-react/yarn.lock | 7 + 10 files changed, 138 insertions(+), 119 deletions(-) create mode 100644 frontend-react/src/components/Title.test.tsx diff --git a/frontend-react/package.json b/frontend-react/package.json index 8b11a6d6a70..9aa05db29af 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -15,6 +15,7 @@ "@rest-hooks/hooks": "^2.0.0", "@rest-hooks/rest": "^2.2.0", "@rest-hooks/test": "^7.1.0", + "@testing-library/user-event": "^13.5.0", "@trussworks/react-uswds": "^2.3.0", "@types/downloadjs": "^1.4.2", "@types/hookrouter": "^2.2.5", @@ -55,7 +56,8 @@ "build:production": "env-cmd -f .env.production craco build", "postbuild:staging": "cp build/index.html build/404.html", "postbuild:production": "cp build/index.html build/404.html", - "test": "react-scripts test", + "test": "craco test", + "test:ci": "CI=true yarn test --coverage", "eject": "react-scripts eject", "lint": "npm-run-all -p lint:eslint lint:prettier", "lint:write": "npm-run-all -p lint:eslint:write lint:prettier:write", diff --git a/frontend-react/src/components/Title.test.tsx b/frontend-react/src/components/Title.test.tsx new file mode 100644 index 00000000000..f761c08209f --- /dev/null +++ b/frontend-react/src/components/Title.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from "@testing-library/react"; + +import Title from "./Title"; + +describe("Title component", () => { + const UNIQUE_TITLE = `Title for test`; + const UNIQUE_PRETITLE = `Unique PreTitle for unit test`; + beforeEach(() => { + render(); + }); + + it("verify title shows", async () => { + expect(await screen.findByText(UNIQUE_TITLE)).toBeInTheDocument(); + expect(await screen.findByText(UNIQUE_PRETITLE)).toBeInTheDocument(); + }); +}); diff --git a/frontend-react/src/content/content.json b/frontend-react/src/content/content.json index 5939fab29b3..27347a4b6ec 100644 --- a/frontend-react/src/content/content.json +++ b/frontend-react/src/content/content.json @@ -105,7 +105,7 @@ "imgAlt": "Map of the U.S. showing states and territories where ReportStream is currently live", "linkInternal": "/how-it-works/where-were-live" } - ] + ] }, { "title": "Interested in learning more about ReportStream?", @@ -115,20 +115,5 @@ "buttonText": "Get in touch", "buttonUrlSubject": "?subject=I'm interested in learning more about ReportStream" } - ], - - "freeSecure": [ - { - "title": "Free and created by the CDC", - "summary": "Developed for COVID-19 test data and public health departments, ReportStream is 100% free.", - "icon": "cdc-logo.svg", - "iconDescription": "CDC logo" - }, - { - "title": "Safe and secure", - "summary": "Test results and patient data are securely stored and protected by two-factor authentication, database encryption, and HTTPS.", - "icon": "shield.svg", - "iconDescription": "Icon of a shield" - } ] } diff --git a/frontend-react/src/pages/home/Home.test.tsx b/frontend-react/src/pages/home/Home.test.tsx index 99fa83f33fd..b5d1995ddcb 100644 --- a/frontend-react/src/pages/home/Home.test.tsx +++ b/frontend-react/src/pages/home/Home.test.tsx @@ -9,21 +9,23 @@ describe("Home rendering", () => { render(<Home />); }); - test("Container renders", () => { - expect(screen.getByTestId("container")).toBeInTheDocument(); + test("Container renders", async () => { + expect(await screen.getByTestId("container")).toBeInTheDocument(); }); test("Renders correct number of elements", async () => { - content.sections.forEach(async (section) => { - expect(await screen.findAllByTestId("feature")).toHaveLength( - section.features?.length || 0 - ); - }); + // these tests require each new feature section has a `data-testid="feature"` set! + + // note: forEach() is not async friendly + for (const eachSection of content.sections) { + for (const eachFeature of eachSection.features) { + // make sure each feature for each section appears somewhere on the page. + expect(await screen.findByText(eachFeature.title)).toBeValid(); + } + } + expect(await screen.findAllByTestId("section")).toHaveLength( - content.sections.length - ); - expect(await screen.findAllByTestId("free-secure")).toHaveLength( - content.freeSecure.length + content.sections.length + content.liveMapContact.length ); }); }); diff --git a/frontend-react/src/pages/home/Home.tsx b/frontend-react/src/pages/home/Home.tsx index ad61c792f8c..3ae0bcef212 100644 --- a/frontend-react/src/pages/home/Home.tsx +++ b/frontend-react/src/pages/home/Home.tsx @@ -21,7 +21,7 @@ export const Home = () => { return ( <section data-testid="section" - key={`section=${sectionIndex}`} + key={`home-${sectionIndex}`} className="usa-section margin-y-0 tablet:padding-top-6 tablet:padding-bottom-3" > <div className="grid-row grid-gap"> @@ -52,7 +52,7 @@ export const Home = () => { return ( <section data-testid="section" - key={`section=${sectionIndex}`} + key={`livemap-${sectionIndex}`} className="usa-section margin-y-0 tablet:padding-top-2 tablet:padding-bottom-2" > <div className="grid-row grid-gap"> diff --git a/frontend-react/src/pages/tos-sign/SuccessPage.test.tsx b/frontend-react/src/pages/tos-sign/SuccessPage.test.tsx index d58b40ffeac..54a2470d0ac 100644 --- a/frontend-react/src/pages/tos-sign/SuccessPage.test.tsx +++ b/frontend-react/src/pages/tos-sign/SuccessPage.test.tsx @@ -33,20 +33,18 @@ describe("Basic rendering", () => { test("Data is displayed", () => { const name = screen.getByText( - `Full name: ${mockData.firstName} ${mockData.lastName}`, + `${mockData.firstName} ${mockData.lastName}`, { exact: false } ); - const email = screen.getByText(`Email: ${mockData.email}`, { + const email = screen.getByText(mockData.email, { + exact: false, + }); + const territory = screen.getByText(mockData.territory, { + exact: false, + }); + const organizationName = screen.getByText(mockData.organizationName, { exact: false, }); - const territory = screen.getByText( - `State or territory: ${mockData.territory}`, - { exact: false } - ); - const organizationName = screen.getByText( - `Organization name: ${mockData.organizationName}`, - { exact: false } - ); expect(name).toBeInTheDocument(); expect(email).toBeInTheDocument(); diff --git a/frontend-react/src/pages/tos-sign/SuccessPage.tsx b/frontend-react/src/pages/tos-sign/SuccessPage.tsx index 17e28f50d31..432ab906d86 100644 --- a/frontend-react/src/pages/tos-sign/SuccessPage.tsx +++ b/frontend-react/src/pages/tos-sign/SuccessPage.tsx @@ -58,8 +58,8 @@ function SuccessPage({ data }: { data: AgreementBody | null }) { Registration request submitted </h4> <p className="usa-alert__text"> - <strong>Name:</strong> {data.firstName}{" "} - {data.lastName} + <strong>Name:</strong>{" "} + {`${data.firstName} ${data.lastName}`} <br /> <strong>Email:</strong> {data.email} <br /> diff --git a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx index e124c82f39e..1443130dbf4 100644 --- a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx +++ b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx @@ -1,12 +1,18 @@ -import { fireEvent, render, screen } from "@testing-library/react"; +import { + fireEvent, + render, + screen, + waitForElementToBeRemoved, + waitFor, +} from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { BrowserRouter } from "react-router-dom"; -import site from "../../content/site.json"; - import TermsOfServiceForm from "./TermsOfServiceForm"; describe("Basic rendering", () => { beforeEach(() => { + process.env.REACT_APP_SECRET = "fake secret"; render( <BrowserRouter> <TermsOfServiceForm /> @@ -14,92 +20,86 @@ describe("Basic rendering", () => { ); }); - test("Title renders", () => { - const preTitle = screen.getByText("Account registration"); - const title = screen.getByText( - "Register your organization with ReportStream" - ); - - expect(preTitle).toBeInTheDocument(); - expect(title).toBeInTheDocument(); - }); - - /* INFO: - FormGroup, Label, TextInput, Dropdown, and Checkbox, and Button rendering tests should be - handled by the trussworks/USWDS component library */ - - test("Required fields show error when you submit them as empty", () => { - fireEvent.click(screen.getByText("Submit registration")); - expect( - screen.getByText("First name is a required field") - ).toBeInTheDocument(); + it("Title renders", async () => { expect( - screen.getByText("Last name is a required field") + await screen.findByText("Account registration") ).toBeInTheDocument(); expect( - screen.getByText("Email is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText("Organization is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText( - "You must agree to the Terms of Service before using ReportStream" + await screen.findByText( + "Register your organization with ReportStream" ) ).toBeInTheDocument(); }); - test("Required fields remove error once field is filled in and re-submitted", () => { - const button = screen.getByText("Submit registration"); - fireEvent.click(button); + test("Required fields remove error once field is filled in and re-submitted", async () => { + const DATA = [ + { + dataTestId: "first-name", + errorMsg: "First name is a required", + }, + { + dataTestId: "last-name", + errorMsg: "Last name is a required", + }, + { + dataTestId: "email", + errorMsg: "Email is a required field", + }, + { + dataTestId: "organization-name", + errorMsg: "Organization is a required", + }, + ]; + const submitBtn = await screen.getByTestId("submit"); - expect( - screen.getByText("First name is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText("Last name is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText("Email is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText("Organization is a required field") - ).toBeInTheDocument(); - expect( - screen.getByText( - "You must agree to the Terms of Service before using ReportStream" - ) - ).toBeInTheDocument(); + for (const eachItem of DATA) { + // clear item, click submit, make sure error is there. + const inputField = await screen.getByTestId(eachItem.dataTestId); - const firstNameInput = screen.getByAltText("First name input"); - const lastNameInput = screen.getByAltText("Last name input"); - const emailInput = screen.getByAltText("Email input"); - const organizationInput = screen.getByAltText("Organization input"); - const agreedInput = screen.getByAltText("Agreed checkbox"); + // fireEvent.change(inputField, {target: {value: " "}}); + fireEvent.change(inputField, { target: { value: "" } }); - fireEvent.change(firstNameInput, { target: { value: "Kevin" } }); - fireEvent.change(lastNameInput, { target: { value: "Haube" } }); - fireEvent.change(emailInput, { - target: { value: site.orgs.CDC.email }, - }); - fireEvent.change(organizationInput, { target: { value: "Foobar" } }); - fireEvent.click(agreedInput); - fireEvent.click(button); + userEvent.click(submitBtn); + expect( + screen.queryByText(eachItem.errorMsg, { exact: false }) + ).toBeInTheDocument(); + // now fill in and see if error messag is cleared + // fireEvent.change(inputField, {target: {value: "test@example.com"}}); + userEvent.type(inputField, "test@example.com"); + + userEvent.click(submitBtn); + expect( + screen.queryByText(eachItem.errorMsg, { exact: false }) + ).not.toBeInTheDocument(); + + // leave it cleared. If every field has a valid value, then last click on submit button will submit. + fireEvent.change(inputField, { target: { value: "" } }); + + userEvent.click(submitBtn); + expect( + screen.queryByText(eachItem.errorMsg, { exact: false }) + ).toBeInTheDocument(); + } + + // the agree checkbox is the exception that mucks everything up + const agreeErrorMsg = "must agree to the Terms of Service"; + const agreedInput = screen.getByTestId("agree"); + userEvent.click(agreedInput); + expect(agreedInput).toBeChecked(); + userEvent.click(submitBtn); + // this is "Visible" because it's using a hidden tag unlike other error messages + // "<ErrorMessage>" vs "<ErrorMessageWithFlag>" .. this drove me nuts writing this test expect( - screen.queryByAltText("First name is a required field") - ).toBeFalsy(); - expect( - screen.queryByAltText("Last name is a required field") - ).toBeFalsy(); - expect(screen.queryByAltText("Email is a required field")).toBeFalsy(); - expect( - screen.queryByAltText("Organization is a required field") - ).toBeFalsy(); + screen.queryByText(agreeErrorMsg, { exact: false }) + ).not.toBeVisible(); + + // toggle it off + userEvent.click(agreedInput); + expect(agreedInput).not.toBeChecked(); + userEvent.click(submitBtn); expect( - screen.queryByAltText( - "You must agree to the Terms of Service before using ReportStream" - ) - ).toBeFalsy(); + screen.queryByText(agreeErrorMsg, { exact: false }) + ).toBeVisible(); }); }); diff --git a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.tsx b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.tsx index fcd5621dfa3..d1aabf23947 100644 --- a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.tsx +++ b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.tsx @@ -266,6 +266,7 @@ function TermsOfServiceForm() { <Label htmlFor="title">Job Title</Label> <TextInput id="title" + data-testid="title" name="title" type="text" value={title} @@ -282,6 +283,7 @@ function TermsOfServiceForm() { <TextInput alt="First name input" id="first-name" + data-testid="first-name" name="first-name" type="text" value={firstName} @@ -302,6 +304,7 @@ function TermsOfServiceForm() { <TextInput alt="Last name input" id="last-name" + data-testid="last-name" name="last-name" type="text" value={lastName} @@ -322,6 +325,7 @@ function TermsOfServiceForm() { <TextInput alt="Email input" id="email" + data-testid="email" name="email" type="email" value={email} @@ -348,6 +352,7 @@ function TermsOfServiceForm() { <TextInput alt="Organization input" id="organization-name" + data-testid="organization-name" name="organization-name" type="text" value={organizationName} @@ -367,6 +372,7 @@ function TermsOfServiceForm() { </Label> <Dropdown id="input-dropdown" + data-testid="states-dropdown" name="states-dropdown" value={territory} onChange={( @@ -393,6 +399,7 @@ function TermsOfServiceForm() { alt="Agreed checkbox" className="padding-top-3" id="multi-state" + data-testid="multi-state" name="multi-state" label="My organization operates in multiple states" onChange={( @@ -407,6 +414,7 @@ function TermsOfServiceForm() { <FormGroup error={agreeErrorFlag}> <Checkbox id="agree" + data-testid="agree" name="agree" onChange={( e: React.ChangeEvent<HTMLInputElement> @@ -433,6 +441,7 @@ function TermsOfServiceForm() { <Button form="tos-agreement" type="submit" + data-testid="submit" disabled={submitting} > Submit registration diff --git a/frontend-react/yarn.lock b/frontend-react/yarn.lock index cf439cda663..4bc9660e420 100644 --- a/frontend-react/yarn.lock +++ b/frontend-react/yarn.lock @@ -1951,6 +1951,13 @@ "@babel/runtime" "^7.12.5" "@testing-library/dom" "^8.0.0" +"@testing-library/user-event@^13.5.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295" + integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg== + dependencies: + "@babel/runtime" "^7.12.5" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" From eddda5f5f5d7f919f92deebea18e498482496b51 Mon Sep 17 00:00:00 2001 From: Carlos Felix <63804190+carlosfelix2@users.noreply.github.com> Date: Fri, 10 Dec 2021 12:40:43 -0500 Subject: [PATCH 15/20] Added check for last modified time to settings CLI (#3403) * Added check for last modified time to settings CLI --- prime-router/build.gradle.kts | 5 +- .../getting-started/faster-development.md | 2 +- .../src/main/kotlin/azure/HttpUtilities.kt | 11 ++- .../main/kotlin/cli/LookupTableCommands.kt | 19 +++- .../src/main/kotlin/cli/SettingCommands.kt | 88 ++++++++++++++++--- prime-router/start_func.sh | 8 +- 6 files changed, 109 insertions(+), 24 deletions(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index 6f84035063f..c3f1efa756d 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -110,8 +110,9 @@ tasks.clean { delete("target") // clean up all the old event files in the SOAP set up doLast { - val eventsDir = File("../.environment/soap_service/soap/event/v1/") - if (eventsDir.exists()) { + val eventsDir = File("../.environment/soap_service/soap/event/v1") + if (eventsDir.exists() && eventsDir.isDirectory && eventsDir.listFiles().isNotEmpty()) { + // Note FileUtils does not like when the folder is empty. FileUtils.listFiles(eventsDir, arrayOf("event"), true).forEach { it.delete() } diff --git a/prime-router/docs/getting-started/faster-development.md b/prime-router/docs/getting-started/faster-development.md index c4555b4d2f3..ca0948690bd 100644 --- a/prime-router/docs/getting-started/faster-development.md +++ b/prime-router/docs/getting-started/faster-development.md @@ -21,7 +21,7 @@ a one time procedure and only needs to be run at workstation startup or when you ```bash docker-compose -f docker-compose.build.yml up --detach -docker-compose up --scale prime_dev=0 --scale settings=0 --scale web_receiver=0 --detach +docker-compose up --scale prime_dev=0 --detach ``` ### Running the Azure functions diff --git a/prime-router/src/main/kotlin/azure/HttpUtilities.kt b/prime-router/src/main/kotlin/azure/HttpUtilities.kt index 7486afdfb68..75ba11d2731 100644 --- a/prime-router/src/main/kotlin/azure/HttpUtilities.kt +++ b/prime-router/src/main/kotlin/azure/HttpUtilities.kt @@ -26,6 +26,11 @@ class HttpUtilities { const val watersApi = "/api/waters" const val tokenApi = "/api/token" + /** + * Last modified time header value formatter. + */ + val lastModifiedFormatter: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME + fun okResponse( request: HttpRequestMessage<String?>, responseBody: String, @@ -151,10 +156,10 @@ class HttpUtilities { ) { if (lastModified == null) return // https://datatracker.ietf.org/doc/html/rfc7232#section-2.2 defines this header format - val lastModifiedFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss") - // Convert to GMT timezone + + // Convert to UTC timezone val lastModifiedGMT = OffsetDateTime.ofInstant(lastModified.toInstant(), ZoneOffset.UTC) - val lastModifiedFormatted = "${lastModifiedGMT.format(lastModifiedFormatter)} GMT" + val lastModifiedFormatted = lastModifiedGMT.format(lastModifiedFormatter) builder.header(HttpHeaders.LAST_MODIFIED, lastModifiedFormatted) } diff --git a/prime-router/src/main/kotlin/cli/LookupTableCommands.kt b/prime-router/src/main/kotlin/cli/LookupTableCommands.kt index 5ddce4ab8a0..14cce138e11 100644 --- a/prime-router/src/main/kotlin/cli/LookupTableCommands.kt +++ b/prime-router/src/main/kotlin/cli/LookupTableCommands.kt @@ -790,6 +790,15 @@ class LookupTableLoadAllCommand : GenericLookupTableCommand( private val connRetries by option("-r", "--retries", help = "Number of seconds to retry waiting for the API") .int().default(30) + /** + * Number of connection retries. + */ + private val checkLastModified by option( + "--check-last-modified", + help = "Update settings only if input file is newer" + ) + .flag(default = false) + /** * The reference to the table creator command. */ @@ -803,9 +812,11 @@ class LookupTableLoadAllCommand : GenericLookupTableCommand( CommandUtilities.waitForApi(environment, connRetries) // Get the list of current tables to only update or create new ones. - val tableUpdateTimes = LookupTableEndpointUtilities(environment).fetchList().map { - it.tableName to it.createdAt - }.toMap() + val tableUpdateTimes = if (checkLastModified) + LookupTableEndpointUtilities(environment).fetchList().map { + it.tableName to it.createdAt + }.toMap() + else emptyMap() // Loop through all the files val files = try { @@ -819,7 +830,7 @@ class LookupTableLoadAllCommand : GenericLookupTableCommand( var needToLoad = true // If we have a table in the database then only update it if the last modified time of the file is // greater than the created time in the database. - if (tableUpdateTimes.contains(tableName) && tableUpdateTimes[tableName] != null) { + if (checkLastModified && tableUpdateTimes.contains(tableName) && tableUpdateTimes[tableName] != null) { val fileUpdatedTime = Instant.ofEpochMilli(it.lastModified()) if (!fileUpdatedTime.isAfter(tableUpdateTimes[tableName]!!.toInstant())) { needToLoad = false diff --git a/prime-router/src/main/kotlin/cli/SettingCommands.kt b/prime-router/src/main/kotlin/cli/SettingCommands.kt index 5704207d99d..345098b42d4 100644 --- a/prime-router/src/main/kotlin/cli/SettingCommands.kt +++ b/prime-router/src/main/kotlin/cli/SettingCommands.kt @@ -16,6 +16,7 @@ import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.required import com.github.ajalt.clikt.parameters.types.choice +import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.inputStream import com.github.ajalt.clikt.parameters.types.int import com.github.ajalt.clikt.parameters.types.outputStream @@ -27,16 +28,21 @@ import com.github.kittinunf.fuel.core.extensions.authentication import com.github.kittinunf.fuel.json.FuelJson import com.github.kittinunf.fuel.json.responseJson import com.github.kittinunf.result.Result +import com.google.common.net.HttpHeaders import gov.cdc.prime.router.DeepOrganization import gov.cdc.prime.router.Organization import gov.cdc.prime.router.Receiver import gov.cdc.prime.router.Sender +import gov.cdc.prime.router.azure.HttpUtilities import gov.cdc.prime.router.azure.OrganizationAPI import gov.cdc.prime.router.azure.ReceiverAPI import gov.cdc.prime.router.azure.SenderAPI import gov.cdc.prime.router.common.Environment import org.apache.http.HttpStatus +import java.io.File import java.io.InputStream +import java.time.OffsetDateTime +import java.time.format.DateTimeParseException private const val apiPath = "/api/settings" private const val dummyAccessToken = "dummy" @@ -192,13 +198,25 @@ abstract class SettingCommand( } } - fun readInput(): String { - if (inStream == null) abort("Missing input file") - val input = String(inStream!!.readAllBytes()) + /** + * Read the contents of an [inputStream]. + * @return the file contents + */ + fun readInput(inputStream: InputStream? = inStream): String { + if (inputStream == null) abort("Missing input file") + val input = String(inputStream.readAllBytes()) if (input.isBlank()) abort("Blank input") return input } + /** + * Read the contents [file]. + * @return the file contents + */ + fun readInput(file: File): String { + return readInput(file.inputStream()) + } + fun writeOutput(output: String) { outStream.write(output.toByteArray()) } @@ -518,8 +536,11 @@ class PutMultipleSettings : SettingCommand( help = "set all settings from a 'organizations.yml' file" ) { - override val inStream by option("-i", "--input", help = "Input from file", metavar = "<file>") - .inputStream() + /** + * Input file with the settings. + */ + private val inputFile by option("-i", "--input", help = "Input from file", metavar = "<file>") + .file(true, mustBeReadable = true).required() /** * Number of connection retries. @@ -527,6 +548,15 @@ class PutMultipleSettings : SettingCommand( private val connRetries by option("-r", "--retries", help = "Number of seconds to retry waiting for the API") .int().default(30) + /** + * Number of connection retries. + */ + private val checkLastModified by option( + "--check-last-modified", + help = "Update settings only if input file is newer" + ) + .flag(default = false) + override fun run() { val environment = Environment.get(env) val accessToken = getAccessToken(environment) @@ -535,13 +565,45 @@ class PutMultipleSettings : SettingCommand( TermUi.echo("Waiting for the API at ${environment.url} to be available...") CommandUtilities.waitForApi(environment, connRetries) - val results = putAll(environment, accessToken) - val output = "${results.joinToString("\n")}\n" - writeOutput(output) + if (!checkLastModified || (checkLastModified && isFileUpdated(environment))) { + TermUi.echo("Loading settings from ${inputFile.absolutePath}...") + val results = putAll(environment, accessToken) + val output = "${results.joinToString("\n")}\n" + writeOutput(output) + } else { + TermUi.echo("No new updates found for settings.") + } + } + + /** + * Check if the settings from a file are newer than the data stored in the database for the + * given [environment]. + * @return true if the file settings are newer or there is nothing in the database, false otherwise + */ + private fun isFileUpdated(environment: Environment): Boolean { + val url = formPath(environment, Operation.LIST, SettingType.ORG, "") + val (_, response, result) = Fuel.head(url).authentication() + .bearer(getAccessToken(environment)).response() + return when (result) { + is Result.Success -> { + if (response[HttpHeaders.LAST_MODIFIED].isNotEmpty()) { + try { + val apiModifiedTime = OffsetDateTime.parse( + response[HttpHeaders.LAST_MODIFIED].first(), + HttpUtilities.lastModifiedFormatter + ) + apiModifiedTime.toInstant().toEpochMilli() < inputFile.lastModified() + } catch (e: DateTimeParseException) { + error("Unable to decode last modified data from API call. $e") + } + } else true // We have no last modified time, which means the DB is empty + } + else -> error("Unable to fetch settings last update time from API. $result") + } } private fun putAll(environment: Environment, accessToken: String): List<String> { - val deepOrgs = readYaml() + val deepOrgs = readYaml(inputFile) val results = mutableListOf<String>() // Put orgs deepOrgs.forEach { deepOrg -> @@ -562,8 +624,12 @@ class PutMultipleSettings : SettingCommand( return results } - private fun readYaml(): List<DeepOrganization> { - val input = readInput() + /** + * Read the settings from a YAML file. + * @return the settings + */ + private fun readYaml(file: File): List<DeepOrganization> { + val input = readInput(file.inputStream()) return yamlMapper.readValue(input) } } diff --git a/prime-router/start_func.sh b/prime-router/start_func.sh index 4fd3f490f0f..d13b092f0e7 100644 --- a/prime-router/start_func.sh +++ b/prime-router/start_func.sh @@ -30,13 +30,15 @@ function load_config() { top_dir=$function_folder/../.. test_config_dir=$top_dir/resources/test fatjar=$top_dir/libs/prime-router-0.1-SNAPSHOT-all.jar - java -jar $fatjar lookuptables loadall -d $test_config_dir/metadata/tables -r 60 | awk '{print "[LOAD TABLES] " $0}' + echo "Loading lookup tables..." + java -jar $fatjar lookuptables loadall -d $test_config_dir/metadata/tables -r 60 --check-last-modified # Note the settings require the full metadata catalog to be in place, so run last - java -jar $fatjar multiple-settings set -i $function_folder/settings/organizations.yml -r 60 | awk '{print "[LOAD SETTINGS] " $0}' + echo "Loading organization settings..." + java -jar $fatjar multiple-settings set -i $function_folder/settings/organizations.yml -r 60 --check-last-modified } # Load the configuration in the background. It will wait for the API to start the loading. -load_config & +load_config | awk '{print "[LOAD CONFIG] " $0}' & # Run the functions func host start --cors http://localhost:8090,http://localhost:3000 --language-worker -- "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" \ No newline at end of file From a7d7e5dbf19db80e63db221055e88387d1fdacd9 Mon Sep 17 00:00:00 2001 From: TomNUSDS <74203452+TomNUSDS@users.noreply.github.com> Date: Fri, 10 Dec 2021 10:49:40 -0800 Subject: [PATCH 16/20] Run automated checks on regular PR (NOT master or production) (#3404) * Run automated checks on regular PR (NOT master or production) * Remove unused includes --- .github/workflows/build_frontend.yaml | 4 ++++ frontend-react/package.json | 2 +- .../src/pages/tos-sign/TermsOfServiceForm.test.tsx | 8 +------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build_frontend.yaml b/.github/workflows/build_frontend.yaml index a4bbd3e36da..d57c41f7bb7 100644 --- a/.github/workflows/build_frontend.yaml +++ b/.github/workflows/build_frontend.yaml @@ -60,5 +60,9 @@ jobs: - name: Build staging fallthrough for PR branch (conditional check) if: (!(github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production')) + working-directory: ./frontend-react run: | + yarn lint:prettier + yarn lint:eslint + yarn test:ci yarn build:staging diff --git a/frontend-react/package.json b/frontend-react/package.json index 9aa05db29af..50e81a8d13f 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -1,6 +1,6 @@ { "name": "react-frontend", - "version": "0.1.0", + "version": "0.1.1", "private": true, "npmClient": "yarn", "proxy": "http://localhost:7071", diff --git a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx index 1443130dbf4..2d6449c8465 100644 --- a/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx +++ b/frontend-react/src/pages/tos-sign/TermsOfServiceForm.test.tsx @@ -1,10 +1,4 @@ -import { - fireEvent, - render, - screen, - waitForElementToBeRemoved, - waitFor, -} from "@testing-library/react"; +import { fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { BrowserRouter } from "react-router-dom"; From 080de6d4c567cd02163693b6f82215cecf48cc74 Mon Sep 17 00:00:00 2001 From: Matt Armstrong <mattarmstrong430@gmail.com> Date: Fri, 10 Dec 2021 16:43:07 -0500 Subject: [PATCH 17/20] Updated gitleaks version, commands, and flags (#3397) * ...commit actually created by Matt Armstrong Co-authored-by: Chris Winters <christopher.m.winters@omb.eop.gov> --- .environment/gitleaks/run-gitleaks.sh | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.environment/gitleaks/run-gitleaks.sh b/.environment/gitleaks/run-gitleaks.sh index 62c5dce655b..6c558793d75 100755 --- a/.environment/gitleaks/run-gitleaks.sh +++ b/.environment/gitleaks/run-gitleaks.sh @@ -42,16 +42,18 @@ function note() { } # Use a well known, stable version -GITLEAKS_IMG_NAME="zricethezav/gitleaks:v7.5.0" +GITLEAKS_IMG_NAME="zricethezav/gitleaks:v8.2.0" REPO_ROOT=$(git rev-parse --show-toplevel) CONTAINER_SOURCE_LOCATION="/repo" CONTAINER_LOCATION="repo" VERBOSE=${VERBOSE:-0} +SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" REPORT_JSON="gitleaks.report.json" LOGFILE="gitleaks.log" REPO_CONFIG_PATH=".environment/gitleaks/gitleaks-config.toml" +CONFIG_FILE="gitleaks-config.toml" # Run gitleaks locally if installed LOCAL_GITLEAKS=0 @@ -62,25 +64,25 @@ fi function base_command() { if [[ ${LOCAL_GITLEAKS?} == 1 ]]; then echo "running gitleaks locally" - gitleaks \ - --path="${REPO_ROOT?}" \ - --repo-config-path="${REPO_CONFIG_PATH?}" \ - --report="${REPO_ROOT?}/${REPORT_JSON?}" \ + gitleaks protect \ + --source="${REPO_ROOT?}" \ + --report-path="${REPO_ROOT?}/${REPORT_JSON?}" \ + --config="${SCRIPT_DIR?}/${CONFIG_FILE?}" \ + --report-format "json" \ $(if [[ ${VERBOSE?} != 0 ]]; then echo "--verbose"; else echo ""; fi) \ - $1 \ - 2>"${LOGFILE?}" + $1 else echo "running gitleaks in docker" docker run \ -v "${REPO_ROOT?}:${CONTAINER_SOURCE_LOCATION?}" \ --rm \ - "${GITLEAKS_IMG_NAME?}" \ - --path="${CONTAINER_LOCATION?}" \ - --repo-config-path="${REPO_CONFIG_PATH?}" \ - --report="${CONTAINER_LOCATION?}/${REPORT_JSON?}" \ + "${GITLEAKS_IMG_NAME?}" protect \ + --source="${CONTAINER_SOURCE_LOCATION?}" \ + --report-path="${CONTAINER_SOURCE_LOCATION?}/${REPORT_JSON?}" \ + --config="${CONTAINER_SOURCE_LOCATION?}/${REPO_CONFIG_PATH?}" \ + --report-format "json" \ $(if [[ ${VERBOSE?} != 0 ]]; then echo "--verbose"; else echo ""; fi) \ - $1 \ - 2>"${LOGFILE?}" + $1 fi RC=$? @@ -91,7 +93,7 @@ function scan_uncommitted() { note "Scanning your suggested changes." # NOTE: ironically, the switch to scan your staged (i.e. to be committed) changes is to use the --unstaged switch - base_command "--unstaged" + base_command "--staged" RC=$? From a4f7a42b60155950565a170f720822c35806ecd5 Mon Sep 17 00:00:00 2001 From: Chris Winters <86251310+cwinters-usds@users.noreply.github.com> Date: Fri, 10 Dec 2021 16:46:36 -0500 Subject: [PATCH 18/20] Remove the comment I accidentally kept in with previous (#3409) --- .environment/gitleaks/run-gitleaks.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.environment/gitleaks/run-gitleaks.sh b/.environment/gitleaks/run-gitleaks.sh index 6c558793d75..3019ce2f057 100755 --- a/.environment/gitleaks/run-gitleaks.sh +++ b/.environment/gitleaks/run-gitleaks.sh @@ -91,7 +91,6 @@ function base_command() { function scan_uncommitted() { note "Scanning your suggested changes." - # NOTE: ironically, the switch to scan your staged (i.e. to be committed) changes is to use the --unstaged switch base_command "--staged" From e9e7ccc951ed958d56d6b9d3f27f4b93a842f19f Mon Sep 17 00:00:00 2001 From: Chris Winters <86251310+cwinters-usds@users.noreply.github.com> Date: Sat, 11 Dec 2021 13:18:48 -0500 Subject: [PATCH 19/20] Update log4j due to security vulnerability (#3408) * More about vulnerability: https://www.lunasec.io/docs/blog/log4j-zero-day/ --- prime-router/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prime-router/build.gradle.kts b/prime-router/build.gradle.kts index c3f1efa756d..3ae9a5f2bbe 100644 --- a/prime-router/build.gradle.kts +++ b/prime-router/build.gradle.kts @@ -591,9 +591,9 @@ dependencies { exclude(group = "com.azure", module = "azure-core") exclude(group = "com.azure", module = "azure-core-http-netty") } - implementation("org.apache.logging.log4j:log4j-api:[2.13.2,)") - implementation("org.apache.logging.log4j:log4j-core:[2.13.2,)") - implementation("org.apache.logging.log4j:log4j-slf4j-impl:[2.13.2,)") + implementation("org.apache.logging.log4j:log4j-api:[2.15.0,)") + implementation("org.apache.logging.log4j:log4j-core:[2.15.0,)") + implementation("org.apache.logging.log4j:log4j-slf4j-impl:[2.15.0,)") implementation("org.apache.logging.log4j:log4j-api-kotlin:1.1.0") implementation("com.github.doyaaaaaken:kotlin-csv-jvm:1.2.0") implementation("tech.tablesaw:tablesaw-core:0.42.0") From 9ee7f2a5948b0373c215fb4d24f560c0b77cf8b0 Mon Sep 17 00:00:00 2001 From: David Gage <whytheplatypus@gmail.com> Date: Sun, 12 Dec 2021 19:31:50 -0500 Subject: [PATCH 20/20] #3347 Allow specifying org for submission history (#3356) * Allow specifying org for submission history if authorized to see that organization * Improve queryParam parsing * Update submission smoke test url path Co-authored-by: sean pennino <87096393+sean-usds@users.noreply.github.com> --- .../main/kotlin/azure/SubmissionFunction.kt | 78 +++++++++++++++---- .../kotlin/cli/tests/TestSubmissionsAPI.kt | 2 +- .../kotlin/azure/SubmissionFunctionTests.kt | 2 +- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/prime-router/src/main/kotlin/azure/SubmissionFunction.kt b/prime-router/src/main/kotlin/azure/SubmissionFunction.kt index 0f78cabc505..4cf7aecf1d7 100644 --- a/prime-router/src/main/kotlin/azure/SubmissionFunction.kt +++ b/prime-router/src/main/kotlin/azure/SubmissionFunction.kt @@ -4,6 +4,7 @@ import com.microsoft.azure.functions.HttpMethod import com.microsoft.azure.functions.HttpRequestMessage import com.microsoft.azure.functions.HttpResponseMessage import com.microsoft.azure.functions.annotation.AuthorizationLevel +import com.microsoft.azure.functions.annotation.BindingName import com.microsoft.azure.functions.annotation.FunctionName import com.microsoft.azure.functions.annotation.HttpTrigger import gov.cdc.prime.router.tokens.OktaAuthentication @@ -22,6 +23,64 @@ class SubmissionFunction( private val facade = submissionsFacade private val oktaAuthentication = oktaAuthentication + data class Parameters( + val sort: String, + val cursor: OffsetDateTime?, + val pageSize: Int, + ) { + constructor(query: Map<String, String>) : this( + extractSort(query), + extractCursor(query), + extractPageSize(query), + ) + + companion object { + fun extractSort(query: Map<String, String>): String { + val qSortOrder = query.getOrDefault("sort", "DESC") + return qSortOrder + } + + fun extractCursor(query: Map<String, String>): OffsetDateTime? { + val qResultsAfterDate = query.get("cursor") + return if (qResultsAfterDate != null) { + try { + OffsetDateTime.parse(qResultsAfterDate) + } catch (e: DateTimeParseException) { + throw IllegalArgumentException("cursor must be a valid datetime") + } + } else null + } + + fun extractPageSize(query: Map<String, String>): Int { + val size = query.getOrDefault("pagesize", "10").toIntOrNull() + require(size != null) { "pageSize must be a positive integer" } + return size + } + } + } + + @FunctionName("getOrgSubmissions") + fun organizationSubmissions( + @HttpTrigger( + name = "getOrgSubmissions", + methods = [HttpMethod.GET], + authLevel = AuthorizationLevel.ANONYMOUS, + route = "history/{organization}/submissions" + ) request: HttpRequestMessage<String?>, + @BindingName("organization") organization: String, + ): HttpResponseMessage { + return oktaAuthentication.checkAccess(request, organization, true) { + try { + val (qSortOrder, resultsAfterDate, pageSize) = Parameters(request.queryParameters) + + val submissions = facade.findSubmissionsAsJson(organization, qSortOrder, resultsAfterDate, pageSize) + HttpUtilities.okResponse(request, submissions) + } catch (e: IllegalArgumentException) { + HttpUtilities.badRequestResponse(request, e.message ?: "Invalid Request") + } + } + } + /** * An Azure Function that is triggered at the `/api/submissions/` endpoint * @@ -31,12 +90,12 @@ class SubmissionFunction( * @return a list of submission history results. */ @FunctionName("getSubmissions") - fun run( + fun submissions( @HttpTrigger( name = "getSubmissions", methods = [HttpMethod.GET], authLevel = AuthorizationLevel.ANONYMOUS, - route = "submissions" + route = "history/submissions" ) request: HttpRequestMessage<String?>, ): HttpResponseMessage { return oktaAuthentication.checkAccess(request, "") { @@ -59,20 +118,7 @@ class SubmissionFunction( org = org.removePrefix(oktaSenderGroupPrefix) - // URL Query Parameters - val qSortOrder = request.queryParameters.getOrDefault("sort", "DESC") - - val qResultsAfterDate = request.queryParameters.get("cursor") - val resultsAfterDate = if (qResultsAfterDate != null) { - try { - OffsetDateTime.parse(qResultsAfterDate) - } catch (e: DateTimeParseException) { - throw IllegalArgumentException("cursor must be a valid datetime") - } - } else null - - val pageSize = request.queryParameters.getOrDefault("pagesize", "10").toIntOrNull() - require(pageSize != null) { "pageSize must be a positive integer" } + val (qSortOrder, resultsAfterDate, pageSize) = Parameters(request.queryParameters) val submissions = facade.findSubmissionsAsJson(org, qSortOrder, resultsAfterDate, pageSize) HttpUtilities.okResponse(request, submissions) diff --git a/prime-router/src/main/kotlin/cli/tests/TestSubmissionsAPI.kt b/prime-router/src/main/kotlin/cli/tests/TestSubmissionsAPI.kt index 6aabdd527ca..79679b7d13c 100644 --- a/prime-router/src/main/kotlin/cli/tests/TestSubmissionsAPI.kt +++ b/prime-router/src/main/kotlin/cli/tests/TestSubmissionsAPI.kt @@ -25,7 +25,7 @@ class TestSubmissionsAPI : CoolTest() { ) passed = passed and isValidJsonResponse( - "${environment.url}/api/submissions", + "${environment.url}/api/history/submissions", listOf( "limit" to "10", ), diff --git a/prime-router/src/test/kotlin/azure/SubmissionFunctionTests.kt b/prime-router/src/test/kotlin/azure/SubmissionFunctionTests.kt index 4f6bbcd1d80..36da83d56f3 100644 --- a/prime-router/src/test/kotlin/azure/SubmissionFunctionTests.kt +++ b/prime-router/src/test/kotlin/azure/SubmissionFunctionTests.kt @@ -201,7 +201,7 @@ class SubmissionFunctionTests { SubmissionsFacade( TestSubmissionAccess(testData, mapper) ) - ).run(httpRequestMessage) + ).submissions(httpRequestMessage) // Verify assertThat(response.getStatus()).isEqualTo(it.expectedResponse.status) }