Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation Agnostic Testing #1946

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions decisions/0007-implementation-agnostic-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Implementation-agnostic Testing and Test Harness

Date: 10/06/2023

## Status

Proposed

## Context

In order to support the development of OSCAL tooling, it was decided prototype a unified tool responsible for validating OSCAL implementations against specification requirements.

Currently, only profile resolution has been [formalized into a draft specification](../src/specifications/profile-resolution/profile-resolution-specml.xml).

### Existing Infrastructure

The profile resolver specification currently leverages an in-house XML format known as SpecML, which breaks down a specification into a collection of **sections**, which contain in turn a collection of **requirements**.
Each `<section/>` and `<requirement/>` has a unique `@id` attribute.

The sections and requirements are mirrored in the XSLT implementation's profile resolution unit tests.
Although crucial to the XSLT implementation, these tests are not portable and it would not be simple to use the tests in their current state to validate other implementations.

### Specification Tests

Some specifications such as [CommonMark](https://commonmark.org/) include a [test suite and testing harness](https://github.com/commonmark/commonmark-spec/tree/master/test) to make it possible for implementors to "score" their implementation's conformance to the specification.

## Decision

### SpecML

The specification format will remain unchanged for now.
There is an argument for the format to be replaced or simplified in the future, but the use of `@id` attributes for sections and requirements make linking a test to a example simple.

### Test Suite Data Format
Copy link
Contributor

@aj-stein-nist aj-stein-nist Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: as an aside, did you consider/review the Test Anything Protocol (TAP) or any similar efforts while designing the MVP JSON test data format you are proposing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not heard of this protocol, though it looks like compelling follow-up work. The format seems simple enough to adapt the current output to (perhaps behind a CLI flag). The current output format is arbitrarily chosen as it's "easy enough" to read both as a human and to grep for basic automation.


The test suite will be described using a JSON file with a simple data format.

This file will contain a collection of objects that map to a given spec requirement via `section_id` and `requirement_id` fields.
These objects will further contain a collection of "scenario" objects, each of which containing a `description`, `source_profile_path`, `expected_catalog_path`, and a collection of `selection_expressions`.

For a given scenario, a test runner would be expected to perform profile resolution with the `source_profile_path` and compare selections of the resulting document with the `expected_catalog_path`.
The `selection_expressions` are XPath expressions, though the [test harness](#test-harness) may further constrain the XPath expression's capabilities.

Here is an example test suite made up of one requirement:

```json
[
{
"section_id": "import",
"requirement_id": "req-uri-resolve",
"scenarios": [
{
"description": "Check that group and control titles match, signalling that URIs have been resolved",
"source_profile_path": "requirement-tests/req-include-all-asis.xml",
"expected_catalog_path": "requirement-tests/output-expected/req-include-all-asis_RESOLVED.xml",
"selection_expressions": [
"./oscal:group/oscal:title",
"./oscal:group/oscal:control/oscal:title"
]
}
]
}
]
```

The development of a JSON schema for this format is left as future work.

### Test Harness

A prototype testing harness has been developed, with the capability to report a given profile resolver's compliance to a specification given a [test suite JSON file](#test-suite-data-format).

The prototype harness is built to be as simple as possible, avoiding external libraries.
Python's native XPath capabilities are limited, further constraining the capabilities of the test suite.

## Consequences

Writing specification tests for profile resolution will require significant resources, but will make profile resolution more approachable for implementors and will make changes to the specification more maintainable.

Due to the "requirement based" approach of the specification test suite, new tests can be added gradually.
Test coverage can be determined by determining which requirements do not have tests.
241 changes: 0 additions & 241 deletions src/specifications/profile-resolution/metaschema-datatypes.xsd

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
</x:scenario>
<x:scenario label="6.1.5 Multiple imports | Note that this occurs even if the same catalog is imported multiple times: each distinct import collects controls into a separate selection">
<x:scenario label="Example req-chained-deepA.xml - PENDING&#xA; chained profiles"
pending="chained profiles"><?requirement rq-mulitple-imports ?>
pending="chained profiles"><?requirement rq-multiple-imports ?>
<x:context href="requirement-tests/req-chained-deepA.xml"/>
<x:expect label="Resolution of req-chained-deepA.xml"
select="opr:scrub(.)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ profile:
<section id="URI-multiple">
<head>Multiple imports</head>
<p>Each import directive is processed to produce a set of controls. <req
id="rq-mulitple-imports">Note that this occurs even if the same catalog is imported
id="rq-multiple-imports" level="must">Note that this occurs even if the same catalog is imported
multiple times: each distinct import collects controls into a separate
<int>selection</int></req>: </p>
<tagging whose="source_profile">
Expand Down Expand Up @@ -445,7 +445,7 @@ intermediate:
- ac-3
- ac-4
</tagging>
<p><req id="rq-multiple-merge">The control inclusions are combined and collapsed in the next
<p><req id="rq-multiple-merge" level="must">The control inclusions are combined and collapsed in the next
phase of processing</req>, <term>merge</term>(see <xref rid="merge-phase"/>) . </p>
<p>Multiple imports against the same resource are allowed, and would most commonly occur when the profile author is using <xref rid="mapping"/> to create very specific output.
Multiple imports may result in outputs with clashing control IDs if mapping or the merge directive is not set correctly.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<addresses-requirement requirement-id="req-resolve-profile">When a profile imports a profile,
the subordinate profile SHOULD be resolved first into a catalog using this
specification, before it is imported. </addresses-requirement>
<addresses-requirement requirement-id="rq-mulitple-imports">Note that this occurs even if the same catalog is imported
<addresses-requirement requirement-id="rq-multiple-imports">Note that this occurs even if the same catalog is imported
multiple times: each distinct import collects controls into a separate
selection</addresses-requirement>
<addresses-requirement requirement-id="rq-multiple-merge">The control inclusions are combined and collapsed in the next
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
<statement>If a processor encounters a circular import as described above (self-imports are inherently circular), the processor MUST cease processing and generate an error. </statement>
<test file="requirement-tests/req-circular_import.xml" status="pending">PENDING circular import detection</test>
</requirement>
<requirement id="rq-mulitple-imports">
<requirement id="rq-multiple-imports">
<statement>Note that this occurs even if the same catalog is imported multiple times: each distinct import collects controls into a separate selection</statement>
<test file="requirement-tests/req-chained-deepA.xml" status="pending">PENDING chained profiles</test>
</requirement>
Expand Down
Loading