Skip to content

TestReport Storage

FHIR Frog provides multiple options for storing TestReports.

Storage Backends

File System

Store reports as JSON or XML files:

FileSystemReportStorage storage = new FileSystemReportStorage(
    Path.of("target/fhir-reports")
);
storage.store(testReport, "json");

FHIR Server

Upload reports to a FHIR server:

IGenericClient client = FhirContext.forR4()
    .newRestfulGenericClient("http://localhost:8080/fhir");

ServerReportStorage storage = new ServerReportStorage(client);
storage.store(testReport);

Composite

Store in multiple locations:

CompositeReportStorage storage = new CompositeReportStorage(
    new FileSystemReportStorage(Path.of("reports")),
    new ServerReportStorage(fhirClient)
);
storage.store(testReport);

Configuration

JUnit

@ExtendWith(FhirFrogExtension.class)
@GenerateTestReport(
    format = "json",
    outputDir = "target/reports",
    uploadToServer = true,
    serverUrl = "http://localhost:8080/fhir"
)
class Tests {}

Maven

<configuration>
    <reportDir>target/fhir-reports</reportDir>
    <reportFormat>both</reportFormat>
    <uploadReports>true</uploadReports>
    <reportServerUrl>http://localhost:8080/fhir</reportServerUrl>
</configuration>

CLI

java -jar fhir-frog-cli.jar \
  -t test.json \
  -s http://localhost:8080/fhir \
  -r ./reports \
  -f json \
  --upload-reports

File Organization

By Date

reports/
  2026-03-11/
    patient-crud-123456.json
    practitioner-crud-123457.json
  2026-03-12/
    patient-crud-234567.json

By Test

reports/
  patient-crud/
    2026-03-11-123456.json
    2026-03-11-234567.json
  practitioner-crud/
    2026-03-11-123456.json

Implementation

public class DateBasedStorage implements ReportStorage {
    private final Path baseDir;

    @Override
    public void store(TestReport report, String format) {
        LocalDate date = LocalDate.now();
        Path dateDir = baseDir.resolve(date.toString());
        Files.createDirectories(dateDir);

        String filename = report.getId() + "." + format;
        Path reportPath = dateDir.resolve(filename);

        // Write report
    }
}

Server Storage

Create Report

IGenericClient client = fhirContext.newRestfulGenericClient(serverUrl);
MethodOutcome outcome = client.create()
    .resource(testReport)
    .execute();

String reportId = outcome.getId().getIdPart();

Search Reports

Bundle results = client.search()
    .forResource(TestReport.class)
    .where(TestReport.TEST_SCRIPT.hasId("patient-crud"))
    .returnBundle(Bundle.class)
    .execute();

Update Report

testReport.setStatus(TestReportStatus.COMPLETED);
client.update()
    .resource(testReport)
    .execute();

Retention Policies

Delete Old Reports

public void cleanupOldReports(Path reportDir, int daysToKeep) {
    LocalDate cutoff = LocalDate.now().minusDays(daysToKeep);

    Files.walk(reportDir)
        .filter(Files::isRegularFile)
        .filter(p -> isOlderThan(p, cutoff))
        .forEach(this::deleteQuietly);
}

Archive Reports

public void archiveOldReports(Path reportDir, Path archiveDir) {
    LocalDate cutoff = LocalDate.now().minusDays(30);

    Files.walk(reportDir)
        .filter(Files::isRegularFile)
        .filter(p -> isOlderThan(p, cutoff))
        .forEach(p -> moveToArchive(p, archiveDir));
}

CI/CD Integration

GitLab CI Artifacts

test:
  script:
    - mvn test
  artifacts:
    paths:
      - target/fhir-reports/
    expire_in: 30 days

GitHub Actions

- name: Upload reports
  uses: actions/upload-artifact@v3
  with:
    name: fhir-test-reports
    path: target/fhir-reports/
    retention-days: 30

Store in S3

public class S3ReportStorage implements ReportStorage {
    private final AmazonS3 s3Client;
    private final String bucketName;

    @Override
    public void store(TestReport report, String format) {
        String key = "reports/" + report.getId() + "." + format;
        String content = fhirContext.newJsonParser()
            .encodeResourceToString(report);

        s3Client.putObject(bucketName, key, content);
    }
}

Security

Encrypt Reports

public class EncryptedStorage implements ReportStorage {
    private final ReportStorage delegate;
    private final Cipher cipher;

    @Override
    public void store(TestReport report, String format) {
        String json = fhirContext.newJsonParser()
            .encodeResourceToString(report);
        byte[] encrypted = cipher.doFinal(json.getBytes());

        // Store encrypted bytes
    }
}

Access Control

// Restrict report access
testReport.getMeta().addSecurity()
    .setSystem("http://terminology.hl7.org/CodeSystem/v3-Confidentiality")
    .setCode("R")
    .setDisplay("Restricted");

Best Practices

Multiple Storage

Use composite storage to save reports both locally and on a server for redundancy.

Disk Space

Implement retention policies to prevent disk space issues from accumulated reports.

  1. Backup reports - Store in multiple locations
  2. Implement retention - Delete or archive old reports
  3. Secure storage - Encrypt sensitive test data
  4. Monitor space - Alert on low disk space
  5. Version reports - Track report format changes

Next Steps