Skip to content

Commit

Permalink
Merge branch 'staging' into OCD-4517
Browse files Browse the repository at this point in the history
  • Loading branch information
tmy1313 committed Jan 22, 2025
2 parents 9cf947d + 06081c7 commit 4bcda62
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 96 deletions.
20 changes: 20 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Release Notes

## Version 48.0.0
_21 January 2025_

### Breaking Change
* Remove deprecated activity metadata objectId field

### Features
* Add endpoints to support Criteria Attributes Power BI report
* Clear out security context when each Quartz job finishes
* Give ACB user permission to see activity for functest, stds, svap
* Give ONC user access to CRUD ops on functest, testtools, stds
* Deprecate fields in developer, product, and listing activity metadata

### Bug Fixes
* Stop adding baseline standards valid on cert date
* Improve upload and merge code when file is very very bad
* User certification date from upload to create active cert event

---

## Version 47.7.0
_6 January 2025_

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,6 @@
</Logger>
<Logger name="fixDatadogUrlUptimeAssertionsJobLogger" level="INFO" additivity="false">
<AppenderRef ref="fixDatadogUrlUptimeAssertionsJob" />
<AppenderRef ref="FixDatadogUrlUptimeAssertionsJobJson" />
<AppenderRef ref="fixDatadogUrlUptimeAssertionsJobJson" />
</Logger>
</Loggers>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ chplUrlBegin=https://chpl.healthit.gov
developerUrlPart=/#/organizations/developers/%s
jndiName=java:comp/env/jdbc/openchpl
persistenceUnitName=openchpl
api.version=47.7.0
api.version=48.0.0
api.description=Created by CHPL Development Team. Please submit any questions using the Health IT \
Feedback Form and select the "Certified Health IT Products List (CHPL)" category. <br/>\
See more at <a href="%s" target="_blank">%s</a>
Expand Down
2 changes: 1 addition & 1 deletion chpl/chpl-resources/src/main/resources/jobs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@
<job>
<name>fixDatadogUrlUptimeAssertionsJob</name>
<group>systemJobs</group>
<description>Fix Datadog Url Uptime Assertions Job (BEWARE - THIS JOB CAN ONLY BE RUN ONCE IN EACH DATADOG ENVITRONMENT!)</description>
<description>Fix Datadog Url Uptime Assertions Job (BEWARE - THIS JOB CAN ONLY BE RUN ONCE IN EACH DATADOG ENVIRONMENT!)</description>
<job-class>gov.healthit.chpl.scheduler.job.urluptime.FixDatadogUrlUptimeAssertionsJob</job-class>
<durability>true</durability>
<recover>false</recover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@Log4j2(topic = "serviceBaseUrlListUptimeCreatorJobLogger")
@Component
public class DatadogSyntheticsTestService {
public static final String NOT_EMPTY_REGEX = "/[\\S]+/";
private static final Integer HTTP_STATUS_OK = 200;
private static final String HTTP_METHOD_GET = "GET";
private static final Long SECONDS_IN_A_MINUTE = 60L;
Expand Down Expand Up @@ -110,7 +111,7 @@ public SyntheticsAPITest createSyntheticsTest(String url, List<Long> developerId
.type(SyntheticsAssertionType.STATUS_CODE)),
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.MATCHES)
.target("/[\\S\s]+[\\S]+/")
.target(NOT_EMPTY_REGEX)
.type(SyntheticsAssertionType.BODY))))
.request(new SyntheticsTestRequest()
.url(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
Expand Down Expand Up @@ -61,85 +59,70 @@ public void execute(JobExecutionContext context) throws JobExecutionException {
LOGGER.info("********* Starting the Fix Datadog Url Uptime Assertions Job *********");

datadogSyntheticsTestService.getAllSyntheticsTests().forEach(test -> {
Optional<SyntheticsAssertion> contentHeaderAssertion = getContentHeaderAssertionExist(test.getConfig().getAssertions());
String url = test.getConfig().getRequest().getUrl();

if (contentHeaderAssertion.isPresent()) {

SyntheticsAPITest body = new SyntheticsAPITest()
.config(new SyntheticsAPITestConfig()
.assertions(Arrays.asList(
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.LESS_THAN)
.target(datadogTestTimeout)
.type(SyntheticsAssertionType.RESPONSE_TIME)),
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.IS)
.target(HTTP_STATUS_OK)
.type(SyntheticsAssertionType.STATUS_CODE)),
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.MATCHES)
.target("/[\\S\s]+[\\S]+/")
.type(SyntheticsAssertionType.BODY))))
.request(new SyntheticsTestRequest()
.url(url)
.method(HTTP_METHOD_GET)))
.options(new SyntheticsTestOptions()
.httpVersion(SyntheticsTestOptionsHTTPVersion.ANY)
.minFailureDuration(0L)
.minLocationFailed(1L)
.scheduling(new SyntheticsTestOptionsScheduling()
.timezone(DateUtil.ET_ZONE_ID)
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.MONDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.TUESDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.WEDNESDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.THURSDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.FRIDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime)))
.tickEvery(convertMinutesToSeconds(datadogCheckEveryMinutes)))
.locations(Collections.singletonList(datadogTestLocation))
.message("Failed: " + url)
.type(SyntheticsAPITestType.API)
.name(url)
.tags(test.getTags());

try {
datadogSyntheticsTestService.getApiProvider().getApiInstance().updateAPITest(test.getPublicId(), body);
LOGGER.info("Test updated: {}", url);
} catch (ApiException e) {
LOGGER.error("Could not update test for URL: {}", url, e);
}
} else {
LOGGER.info("Test NOT updated: {}", url);
SyntheticsAPITest body = new SyntheticsAPITest()
.config(new SyntheticsAPITestConfig()
.assertions(Arrays.asList(
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.LESS_THAN)
.target(datadogTestTimeout)
.type(SyntheticsAssertionType.RESPONSE_TIME)),
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.IS)
.target(HTTP_STATUS_OK)
.type(SyntheticsAssertionType.STATUS_CODE)),
new SyntheticsAssertion(new SyntheticsAssertionTarget()
.operator(SyntheticsAssertionOperator.MATCHES)
.target(DatadogSyntheticsTestService.NOT_EMPTY_REGEX)
.type(SyntheticsAssertionType.BODY))))
.request(new SyntheticsTestRequest()
.url(url)
.method(HTTP_METHOD_GET)))
.options(new SyntheticsTestOptions()
.httpVersion(SyntheticsTestOptionsHTTPVersion.ANY)
.minFailureDuration(0L)
.minLocationFailed(1L)
.scheduling(new SyntheticsTestOptionsScheduling()
.timezone(DateUtil.ET_ZONE_ID)
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.MONDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.TUESDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.WEDNESDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.THURSDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime))
.addTimeframesItem(new SyntheticsTestOptionsSchedulingTimeframe()
.day(DatadogDayOfWeek.FRIDAY)
.from(datadogTestStartTime)
.to(datadogTestEndTime)))
.tickEvery(convertMinutesToSeconds(datadogCheckEveryMinutes)))
.locations(Collections.singletonList(datadogTestLocation))
.message("Failed: " + url)
.type(SyntheticsAPITestType.API)
.name(url)
.tags(test.getTags());

try {
datadogSyntheticsTestService.getApiProvider().getApiInstance().updateAPITest(test.getPublicId(), body);
LOGGER.info("Test updated: {}", url);
} catch (ApiException e) {
LOGGER.error("Could not update test for URL: {}", url, e);
}
});

LOGGER.info("********* Completed the Fix Datadog Url Uptime Assertions Job *********");
}


private Optional<SyntheticsAssertion> getContentHeaderAssertionExist(List<SyntheticsAssertion> assertions) {
return assertions.stream()
.filter(assertion -> assertion.getSyntheticsAssertionTarget().getType().equals(SyntheticsAssertionType.HEADER)
&& assertion.getSyntheticsAssertionTarget().getProperty().equals("content-length"))
.findAny();

}

private Long convertMinutesToSeconds(Long minutes) {
return minutes * SECONDS_IN_A_MINUTE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ public CertifiedProductSearchDetails getListingUploadAsListingForUpdate(ListingU
LOGGER.debug("Converted listing upload into CertifiedProductSearchDetails object");

listingNormalizer.normalize(listing, List.of(
baselineStandardAsOfCertificationDayNormalizer, // have to re-add older baseline standards that users might not put in their file
baselineStandardAsOfTodayNormalizer)); // and add the most current baseline standards we've agreed to always add for users
baselineStandardAsOfTodayNormalizer)); // add the most current baseline standards we've agreed to always add for users
LOGGER.debug("Normalized listing upload");
return listing;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void normalize(CertifiedProductSearchDetails listing) {
if (listing.getCertificationResults() != null && listing.getCertificationResults().size() > 0) {
clearDataForUnattestedCriteria(listing);
listing.getCertificationResults().stream()
.forEach(certResult -> populateAdditionalSoftwareIds(certResult.getAdditionalSoftware()));
.forEach(certResult -> normalize(certResult.getAdditionalSoftware()));
}
}

Expand All @@ -38,14 +38,32 @@ private void clearDataForUnattestedCriteria(CertifiedProductSearchDetails listin
.forEach(unattestedCertResult -> unattestedCertResult.getAdditionalSoftware().clear());
}

private void populateAdditionalSoftwareIds(List<CertificationResultAdditionalSoftware> additionalSoftwares) {
private void normalize(List<CertificationResultAdditionalSoftware> additionalSoftwares) {
if (additionalSoftwares != null && additionalSoftwares.size() > 0) {
additionalSoftwares.stream()
.forEach(additionalSoftware -> setEmptyStringFieldsToNull(additionalSoftware));

additionalSoftwares.stream()
.filter(additionalSoftware -> hasListingAsAdditionalSoftware(additionalSoftware))
.forEach(additionalSoftware -> populateAdditionalSoftwareId(additionalSoftware));
}
}

private void setEmptyStringFieldsToNull(CertificationResultAdditionalSoftware additionalSoftware) {
if (StringUtils.isEmpty(additionalSoftware.getGrouping())) {
additionalSoftware.setGrouping(null);
}
if (StringUtils.isEmpty(additionalSoftware.getJustification())) {
additionalSoftware.setJustification(null);
}
if (StringUtils.isEmpty(additionalSoftware.getVersion())) {
additionalSoftware.setVersion(null);
}
if (StringUtils.isEmpty(additionalSoftware.getName())) {
additionalSoftware.setName(null);
}
}

private boolean hasListingAsAdditionalSoftware(CertificationResultAdditionalSoftware additionalSoftware) {
return !StringUtils.isEmpty(additionalSoftware.getCertifiedProductNumber())
&& additionalSoftware.getCertifiedProductId() == null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public CertificationResultNormalizer(CertificationCriterionNormalizer criterionN
}

public void normalize(CertifiedProductSearchDetails listing, List<CertificationResultLevelNormalizer> additionalNormalizers) {
listing.getCertificationResults().stream()
.forEach(certResult -> setEmptyStringFieldsToNull(certResult));

removeCertificationResultsWithNullCriterion(listing);
removeCertificationResultsForDuplicateCriteria(listing);

Expand Down Expand Up @@ -150,6 +153,30 @@ private void setSedTrueIfApplicableToCriteria(CertifiedProductSearchDetails list
.forEach(certResult -> certResult.setSed(true));
}

private void setEmptyStringFieldsToNull(CertificationResult cr) {
if (StringUtils.isEmpty(cr.getApiDocumentation())) {
cr.setApiDocumentation(null);
}
if (StringUtils.isEmpty(cr.getDocumentationUrl())) {
cr.setDocumentationUrl(null);
}
if (StringUtils.isEmpty(cr.getExportDocumentation())) {
cr.setExportDocumentation(null);
}
if (StringUtils.isEmpty(cr.getPrivacySecurityFramework())) {
cr.setPrivacySecurityFramework(null);
}
if (StringUtils.isEmpty(cr.getRiskManagementSummaryInformation())) {
cr.setRiskManagementSummaryInformation(null);
}
if (StringUtils.isEmpty(cr.getServiceBaseUrlList())) {
cr.setServiceBaseUrlList(null);
}
if (StringUtils.isEmpty(cr.getUseCases())) {
cr.setUseCases(null);
}
}

@NoArgsConstructor
private class CertificationResultComparator implements Comparator<CertificationResult> {
private boolean descending = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void normalize(CertifiedProductSearchDetails listing) {
if (!CollectionUtils.isEmpty(listing.getCertificationResults())) {
clearDataForUnattestedCriteria(listing);
listing.getCertificationResults().stream()
.forEach(certResult -> fillInConformanceMethodData(listing, certResult));
.forEach(certResult -> normalize(listing, certResult));
}
}

Expand All @@ -55,11 +55,21 @@ private void clearDataForUnattestedCriteria(CertifiedProductSearchDetails listin
.forEach(unattestedCertResult -> unattestedCertResult.getTestProcedures().clear());
}

private void fillInConformanceMethodData(CertifiedProductSearchDetails listing, CertificationResult certResult) {
private void normalize(CertifiedProductSearchDetails listing, CertificationResult certResult) {
if (!CollectionUtils.isEmpty(certResult.getConformanceMethods())) {
certResult.getConformanceMethods().stream()
.forEach(crcm -> setEmptyStringFieldsToNull(crcm));
}
populateConformanceMethodIds(certResult.getCriterion(), certResult.getConformanceMethods());
populateConformanceMethodRemovalDates(certResult.getCriterion(), certResult.getConformanceMethods());
}

private void setEmptyStringFieldsToNull(CertificationResultConformanceMethod crcm) {
if (StringUtils.isEmpty(crcm.getConformanceMethodVersion())) {
crcm.setConformanceMethodVersion(null);
}
}

private void populateConformanceMethodIds(CertificationCriterion criterion, List<CertificationResultConformanceMethod> conformanceMethods) {
if (!CollectionUtils.isEmpty(conformanceMethods)) {
conformanceMethods.stream()
Expand Down
Loading

0 comments on commit 4bcda62

Please sign in to comment.