Testing a method
Running a method on test data with the harness.
How-to
The test harness runs one method end to end on fixed test data, exactly as the worker would, without the analysis service, the queue or the workbench. It builds the method's image, runs the orchestrator in a container, records resource usage and leaves a result package you can open. This is the first check for any new or changed method; a run inside the platform comes after. Building a method is described in Building a method from the template.
The test harness
test_harness.sh lives in the bf-analysis-jobs root and must be run from there. It needs Docker on the machine and nothing else: no Azure access, no Redis, no API.
cd bf-analysis-jobs
bash test_harness.sh <name>
Each run:
- Creates
/tmp/test_harness/<name>.test/withrecords.jsonlandparams.jsonfrom the test data, and packs it as<name>.test.tar. The job ID is alwaystest. - Builds the image
<name>from<name>/Dockerfile, with the same build context and namedbcdm_forensic_extcontext the worker uses. - Starts a container running
bash /app/orchestrator.sh <name>.test.tarwith/tmp/test_harnessmounted as the working directory, and samples the container's CPU and memory every 10 seconds (STATS_SAMPLE_INTERVALoverrides this). - Waits for the container, prints its log, writes
resource_stats.jsoninto the job directory and copies it out as the metadata sidecar. - Zips the job directory, removes it, and exits with the container's exit code.
Test data
File in test_data/ |
Use |
|---|---|
<name>-params.json |
Required. Becomes the run's params.json |
<name>-records.jsonl |
Optional. Records for this method only |
records.jsonl |
The records used when no method-specific file exists |
records_10.jsonl |
A ten-record set, handy for quick runs |
Only diagnostic-characters and sequence-data-ingest ship their own records; every other method falls back to records.jsonl. To run on another file set TEST_RECORDS_FILE, for example TEST_RECORDS_FILE=test_data/records_10.jsonl bash test_harness.sh <name>.
Write the params file as the workbench would send it: every field name from the method's definition, with title, recordset_title and recordset_descr, and with the value types the form produces (slider values as strings, checkboxes as booleans, multi-selects as lists; see Registering a method). A params file that drifts from the form definition tests something the platform will never send.
What a run produces
| Output | Meaning |
|---|---|
| Exit code | 0 on success; otherwise the container's code, which is the number of the stage that failed (1 to 5) or 404 for a package missing its files |
| Console | The image build, then the container log: a ## Starting N.<stage>.sh marker before each stage and whatever the stage printed |
/tmp/test_harness/<name>.test.zip |
The job directory, laid out exactly as a real result package |
/tmp/test_harness/<name>.test.metadata.json |
The resource-usage sidecar |
The zip is always named <name>.test.zip, for a failed run as well as a successful one; the harness never produces a .failed.zip. A new run overwrites the previous outputs.
Checking a run
- Check the exit code. A non-zero code names the stage; read the stage's output in the console, or extract the error record:
unzip -p /tmp/test_harness/<name>.test.zip '*/error.json'. - On success, unzip the package and confirm the files described on Anatomy of a result package are there:
filtered_records.jsonlwith the count you expect for the filters in the params file, every result file your package stage lists,analysis_charts.htmlwith content when the method draws charts, andanalysis_report.html. - Open
analysis_report.html. The Parameters section should show the params file, the Results counts should match your line counts, the Outputs list should name every file, and the Analysis section should show the charts. - Confirm
analysis_report.pdfis present. If it is missing, the console log containsPDF generation failed; the usual cause is a missing WeasyPrint library in the Dockerfile. - Prove the parameters are applied: change one value in the params file, rerun, and compare the result files. A parameter whose change makes no difference is either unread or unused by the scripts, and should be fixed or removed from the form.
- For runs longer than 10 seconds, check the sidecar has
sample_countabove zero anderrorequal tonull.
Testing inside the platform
Once the harness passes, run the method through the service. Submit a job from the workbench on a small recordset (see Running an analysis). The scheduler is part of the service and runs every 30 seconds in a developer's stack too, so the job moves to QUEUED on its own; local-analysis-scheduled-tasks/2_queue_analysis.sh triggers one scheduler pass immediately if you do not want to wait. 5_list_queue.sh in the same folder lists the queue and results containers, which is the quickest way to confirm the package was uploaded.
The worker is not part of a developer's stack. On a host configured for the environment's containers, run bash execute_job.sh from the bf-analysis-jobs root to process the oldest queued package once; its log and last_run_summary.json are written to the run log directory (RUN_LOG_DIR). Within 30 seconds of the upload the job shows COMPLETE or FAILED in the Analysis panel, and the report preview and download work as they will for users. The administrator's analysis dashboard lists every job and can download the packages, including a failed one.
Good to know
Good to know: The harness builds the image on every run, like the worker. The first build of a new method is slow; later builds reuse cached layers.
Good to know: Every method directory receives the same orchestrator contract, so a method that passes the harness but fails in the platform almost always differs in its inputs: compare the real package's
params.jsonandrecords.jsonlwith your fixtures.Good to know: Some method directories also contain older helpers (
init_test_env.sh,test_orchestrator.sh) that stage a working directory under/tmp/working. The harness is the supported route.