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

add Json schema compilation in smoke test #109

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions src/compose/testing/models_metaschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
<flag ref="id"/>
<model>
<field ref="field-1only"/>
<field>
Copy link
Contributor

Choose a reason for hiding this comment

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

I know I brought this up in #111, but is there some intention we can explain there or here per https://github.com/usnistgov/metaschema-xslt/pull/111/files#r1524912715. It now seems 111 is only a dupe with this change but none of this substantive work in this PR, is there a reason for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it was basically a requirement to get the schema to compile.
without this change we get two fields that try and find a JSON schema definition that doesn't exist.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, so this is needed to fix a test we definitely have a bug on ours hands.

Is this #109 PR connected to a specific issue yet? Just got back from leave and I am talking to Wendell about this on Element/Matrix/Gitter/what-have-you, so I am trying to make sure I understand the context given the other (very good) changes in this PR, but this is basically invalid Metaschema so it caught my attention immediately. If we were purposefully testing "bad model behavior" and negative testing with this model I would let it go, but it seems that was not the intent of this model and behavior and we should identify it and move that out into a bug. Or be very lazy and fix it here, that just causes more confusing git commit reviews later on.

@wendellpiez, thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Given the scope of the PR, I am with AJ. If there is a bug in a metaschema that prohibits generating a JSON Schema, that is not a problem for this Issue but for another one, where we can bring the right attention to bear.

This doesn't mean the problem isn't real, just that we can't cut corners. Demonstration please. :-)

Boy would I love to be able to push a button and have the robots take my schema for a run -- I have that for XSD, can anyone help me with JSON Schema? See #110. Let's do that and determining whether metaschema X makes good JSON Schema will something we can see, not just argue about.

Meanwhile thanks to you both -- @wandmagic please do not hesitate to ask for assistance or further elucidation --

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is the offending part of the schema when make test is run

use AJV to compile the json schema, and it complains about this base-64 malformed reference.

My change allows this to compile, but there may be a better way to fix this

Screenshot 2024-03-14 at 6 02 29 PM

Copy link
Collaborator

@wendellpiez wendellpiez Mar 15, 2024

Choose a reason for hiding this comment

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

Unfortunately the complexity of the system is such that both formal validation (against its own schema) and 'validation in operation' (i.e. try and see what happens) must be conducted. This is because although formal validation goes a long way to ensuring the correctness of the outputs wrt 'intent' (correctness defined by Metaschema semantics), it can't go the full distance.

To deploy and fully test a Metaschema (module) typically entails:

  • Formal validation (against the Metaschema XSD schema) of all Metaschema modules under 'import'
  • Schematron validation of top-level metaschem module to check imports
  • Run the Metaschema to produce derivative artifacts
    • Including XSD, JSON Schema, InspectorXSLT, oscal-cli version, converter XSLTs, documentation stacks, indexes, you name it
  • Unit test and field test any and all of these

We have been doing all this all along, albeit without much automation to help.

Indeed, that is essentially the problem we now have, that without being able both to record and document these processes, and automate testing to be supervised by Metaschema maintainers who are not developers -- we are essentially at a place where the knowledge of how it is done cannot be communicated. (Right, @iMichaela?)

The way I have been trying to address this is by starting to add tests, scripts and readmes in whatever application I need to be working on - recently JSON Schema (#108) and also InspectorXSLT (#98).

Oh look, there is #102 -- which I just merged. It contains work that could be further integrated into CI/CD as well -- I hope this helps.

Copy link
Collaborator

@wendellpiez wendellpiez Mar 15, 2024

Choose a reason for hiding this comment

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

Comment on my comment - note that the stack of tests/validations listed is a funnel. The rules enforced by the Metaschema XSD are very tight. But they are also assumed to be true (to be in force) by the Schematron at the next level down. This means the Schematron is much simpler than it would be otherwise, as it can be built with the XSD rules as "prior knowledge". Same with the next level. Because the Schematron has checked that imports work, the next level doesn't have to fail safe on that. Detecting and preventing the problems at the top of the stack is much easier, faster and easier to tailor than dealing with them at the bottom, where they are typically seen as "garbage out".

All this is in accordance with the 'functional' and 'declarative' mindset cultivated by XML, a descendant of LISP.

The stack is designed so that when a data instance (a Metaschema) passes both XSD and Schematron validation, everything below will be deterministic and 'just work'. So that any problems in unit testing the final XSDs and JSON Schemas etc can be treated as processor bugs to be reported back, and Metaschema authors do not have to be on the hook for processing errors (i.e. jump in and turn into developers).

<use-name>overloaded</use-name>
</field>
<field ref="overloaded">
<use-name>overloaded1</use-name>
</field>
Expand Down
52 changes: 52 additions & 0 deletions src/schema-gen/JSON-schema/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
include ../../testing/make_common.mk

# INCLUDES:
# unit-test - unit testing - XSLT production templates for InspectorXSLT
# spec-test - specification conformance testing - functional runtime tests of the generated XSLT
# xspec - run XSpec tests in designated folder
# clean - clean up designated output folder

# for smoke testing see ../Makefile

# tbd - 'field testing' applying result JSON Schema to known 'working and broken' instances

module_path:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
output_folder:=$(module_path)/test_output
xspec_script=$(realpath $(module_path)/../../../support/xspec-dev/mvn-saxon-xspec-batch-quiet.sh)
xspec_ci_script=$(realpath $(module_path)/../../../support/xspec-dev/mvn-saxon-xspec-batch.sh)
folder=.

.PHONY: test
test: unit-test spec-test ## Run all tests


.PHONY: spec-test
spec-test: ## Run all specification tests
LOGFILE="$(output_folder)/inspector-functional-tests.log" $(xspec_ci_script) \
"folder=$(module_path)/testing/tests/jsonschemagen-mapping-xspec/" \
"report-to=$(output_folder)/jsonschemagen-mapping_report.html" \
"junit-to=$(output_folder)/jsonschemagen-mapping_junit-report.xml" \
"stop-on-error=yes" \
"recurse=yes"

.PHONY: unit-test
unit-test: ## Run all unit tests
LOGFILE="$(output_folder)/inspector-generation-tests.log" $(xspec_ci_script) \
"folder=$(module_path)/testing/tests/jsonschemagen-runtime-xspec" \
"report-to=$(output_folder)/jsonschemagen-runtime_report.html" \
"junit-to=$(output_folder)/jsonschemagen-runtime_junit-report.xml" \
"stop-on-error=yes" \
"recurse=yes"

.PHONY: xspec
xspec: ## Run all *.xspec in a designated folder, quietly - use folder=[folder]
LOGFILE="$(output_folder)/$(folder)-xspec-tests.log" $(xspec_script) \
"baseURI=file:$(module_path)/" \
"folder=$(folder)" \
"report-to=$(output_folder)/inspector-$(folder)-tests_report.html" \
"stop-on-error=no" \
"recurse=yes"

.PHONY: clean
clean: ## Remove test output
rm -fr $(output_folder)/*
2 changes: 1 addition & 1 deletion src/schema-gen/JSON-schema/make-json-schema-metamap.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@
<!--Not supporting float or double-->

<xsl:template priority="2.1" match="*[@as-type = $datatype-map/@as-type]" mode="object-type">
<xsl:variable name="assigned-type" select="$datatype-map[(@as-type|@prefer)=current()/@as-type]/string(.)"/>
<xsl:variable name="assigned-type" select="$datatype-map[@as-type=current()/@as-type]/string(.)"/>
<string key="$ref">#/definitions/{$assigned-type}</string>
</xsl:template>

Expand Down
73 changes: 73 additions & 0 deletions src/schema-gen/JSON-schema/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Testing Metaschema-XSLT JSON Schema production

**Currently only JSON Schema v7 is supported.**

At a future date we aim to support other forms.

## Smoke testing

A JSON Schema, with other schemas, is produced by a pipeline in the parent directory, ../METASCHEMA-ALL-SCHEMAS.xpl, which is also run as a smoke test.

```
pushd ..
make smoke-test
popd
```

The smoke test outputs including a JSON Schema are found in the `test_output` folder (until/unless cleaned out). If a JSON instance cannot be produced, the process will fail.
The smoke test does *not* currently

- test that the JSON functions as a JSON Schema
- test that it conforms to an idea of a JSON Schema ('the standard') or JSON Schema usage patterns

It does, however, confirm that the process terminated successfully with a file output in the expected location.


## Spec testing

In this case, 'spec testing' is testing to see whether the resulting JSON Schema looks like what we think it should look like, in detail.

## Unit testing

Unit tests here focus on end-to-end testing, i.e. per-metaschema mappings from single model input to single JSON Schema output.

The unit testing here is *less* granular than the specification testing.

Neither of these actually test the JSON Schema, only the way in which one is produced.


This implies near-term and longer-term goals:

# JSON Schema generation - planning

## Near-term

Even without running the JSON Schema (a 'field-test' to demonstrate its adequacy for the purpose, i.e. validation), we can test a great deal since we know what that JSON Schema should look like.

I.e., we can test the mapping of Metaschema semantics into JSON by sketching the transformation from Metaschema source to the JSON Schema in its XML precursor format.

- [ ] XSpec the XSLT
- [ ] `make-json-schema-metamap.xsl` for unit testing
- [ ] `../nist-metaschema-MAKE-JSON-SCHEMA-as-xml.xsl` with @external='true' for end to end
- [ ] Flesh out with micro-examples of special cases
- [ ] Deal with `choice` https://github.com/usnistgov/metaschema-xslt/issues/105

cf https://github.com/usnistgov/OSCAL/issues/1989

This will give us something to show that we can generate correct outputs, for given inputs, in the general case.

Note that in this repo, the OSCAL models will *not* be used.

(But it can be used in parallel work in the oscal-xslt repository.)

## Longer-term

"Field test" script able to distinguish between expected-valid and expected-invalid JSON, and report findings.

Something that could be reused in oscal-xslt over OSCAL inputs, for example.

## Punchlist

- [ ] XSpec to test metamap XSLT
- [x] Makefile to run this XSpec using xspec-dev script cf ../InspectorXSLT/Makefile
- [ ] Show tests with proposed solution(s) via PR
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../../../../../testing/xspec-assurance.sch"?>
<?xml-model href="../../../../../util/xspec-fixup.sch"?>
<x:description xmlns:mx="http://csrc.nist.gov/ns/csd/metaschema-xslt"
xmlns="http://example.com/ns/computer"
xmlns:x="http://www.jenitennison.com/xslt/xspec" xmlns:xs="http://www.w3.org/2001/XMLSchema"
stylesheet="../../../make-json-schema-metamap.xsl" xslt-version="3.0">

<!--<x:variable name="mx:makes-a-date" as="function(*)"
select="function($v as item()) as xs:boolean { $v castable as xs:date }"/>-->

<x:scenario label="[A] Comments and PIs are dropped">
<x:scenario label="[A.1] Comment">
<x:variable name="mx:a-comment"><!--comment--></x:variable>
<x:context select="$mx:a-comment"/>
<x:expect label="is dropped" select="()"/>
</x:scenario>
<x:scenario label="[A.2] Processing instruction">
<x:context><?pi type="sample" href="file.css"?></x:context>
<x:expect label="is dropped" select="()"/>
</x:scenario>
</x:scenario>

</x:description>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../../../../../testing/xspec-assurance.sch"?>
<x:description xmlns:mx="http://csrc.nist.gov/ns/csd/metaschema-xslt"
xmlns="http://www.w3.org/2005/xpath-functions"
xmlns:x="http://www.jenitennison.com/xslt/xspec" xmlns:xs="http://www.w3.org/2001/XMLSchema"
run-as="external"
stylesheet="../../../../nist-metaschema-MAKE-JSON-SCHEMA-as-xml.xsl" xslt-version="3.0"
>

<!-- Purpose: accept metaschema input and demonstrate correct production of XPath JSON outputs for a JSON Schema, at the high level -->

<!-- The XSLT under test is a pipeline executing a series of transform() calls
including the composition pipeline, hence @run-as='external' on this XSpec -->

<!-- The unprefixed namespace is bound to the XPath vocabulary for JSON used by the
transformation as a target, hence use of the Q{} notation for XPath here, for convenience and clarity. -->

<!-- This XSpec tests the basics of JSON Schema generation except for its final serialization
into JSON, representing its target using this vocabulary as does the system internally. -->

<x:variable name="models-metaschema" href="../../../../../testing/models_metaschema.xml"/>

<x:scenario label="Metaschema makes an XPath JSON map object, in XML">
<x:context select="$models-metaschema"/>
<x:scenario label="At the root">
<x:expect label="A JSON Map is produced" select="/">
<map>...</map>
</x:expect>
<x:expect label="with a string property marking the JSON as a schema, version draft-07"
select="'http://json-schema.org/draft-07/schema#'"
test="$x:result/*/Q{http://www.w3.org/2005/xpath-functions}string[@key='$schema']/string()"/>
</x:scenario>
</x:scenario>

<!-- for the EVERYTHING metaschema models-metaschema.xml the outputs will look something like this:

<map xmlns="http://www.w3.org/2005/xpath-functions"
xmlns:nm="http://csrc.nist.gov/ns/metaschema">
<string key="$schema">http://json-schema.org/draft-07/schema#</string>
<string key="$id">http://csrc.nist.gov/metaschema/ns/everything/1.0/everything-schema.json</string>
<string key="$comment">NIST Metaschema Everything: JSON Schema</string>
<string key="type">object</string>

JSON Schema see ../jsonschemagen-mapping-xspec/metamap-test.xspec

</map>
-->

</x:description>
36 changes: 36 additions & 0 deletions src/schema-gen/mvn-schemas-xpl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,43 @@ fi

invoke_calabash "${CALABASH_ARGS}"


# Check if npm is installed
if ! command -v npm &> /dev/null; then
echo "npm is not installed. Please install Node.js and npm."
exit 1
else
echo "npm is installed."
fi
# Check if ajv-formats is installed
if ! npm list -g ajv-formats &> /dev/null; then
echo "ajv-formats is not installed. Installing..."
npm install -g ajv-formats
else
echo "ajv-formats is installed."
fi

# Check if ajv-cli is installed
if ! npm list -g ajv-cli &> /dev/null; then
echo "ajv-cli is not installed. Installing..."
npm install -g ajv-cli
else
echo "ajv-cli is installed."
fi

if [ -e "$XSD_FILE" ] && [ -e "$JSONSCHEMA_FILE" ]; then
echo "Wrote XSD to $XSD_FILE" >&2
echo "Wrote JSON schema to $JSONSCHEMA_FILE" >&2
if [ -e "$JSONSCHEMA_FILE" ]; then
ajv compile -s "$JSONSCHEMA_FILE" -c ajv-formats
if [ $? -eq 0 ]; then
echo "JSON schema is valid."
else
echo "JSON schema is invalid."
exit 1
fi
else
echo "JSON schema file $JSONSCHEMA_FILE does not exist."
exit 1
fi
fi
Loading