My response below the pull-quote is … kinda in the weeds, so I thought I’d preface with a high-level thought,
I (think I) get your thought here, and it seems like there are two issues: (a) opam-repo brittleness and the labor cost incurred by opam-repo maintainers (and less importantly by package maintainers/developers), and (b) system costs to -running- those tests in opam-ci.
You didn’t mention #b, so I’ll set it aside, but I’ve wondered if that’s an issue at all.
So to take #a, I’ve felt for a number of years, that the use of extensive testing at at several OCaml versions, and several versions of deps/revdeps,
makes the opam package-collection feel more like a “monorepo” developed by a single organization with a single design and testing philosophy, than what it is, which is a collection of packages developed by people who rarely meet, might differ dramatically in many opinions, and generally are just not well-connected to each other except thru the repo.
I’ve always felt like it is a major strength of the opam-ci process, that (what might appear to be) anal-retentive and draconian (but isn’t!) testing has achieved this level of robustness.
To that end, I felt like adding CRAM tests was a good thing, b/c it tests a different dimension of behaviour of packages – and I’ve seen myself that those tests elicit errors with different versions of OCaml, and different versions of supporting packages, so it doesn’t seem to be superfluous. That said, for sure just doing CRAM/mdx testing blindly, without carefully -cleaning- the output of those tests before comparing, is an antipattern. For sure.
If it’s a consensus view that one should not run mdx tests in opam-ci, I can -easily- disable that. I’ve got separate Make targets for mdx and regular tests.
whilst mdx is great for local tests and even for your ci, i’d recommend against adding the tests to your opam releases. same goes for some but not all cram tests.
the reason is that mdx tests are brittle. they have caused many errors in the opam-repository ci (and the same errors would appear on user machines who would use the testing feature of opam).
- errors because the output depends on timing or other environment (pipe the output through
sed to remove all timing, path, etc. information)
- errors because the output of mdx changed (they started escaping some characters, they changed the line-wrapping logic, etc.)
- errors because some formatting rule changed (line-wrapping, filename quoting, float printing, etc.)
from what i can tell reviewing opam-repository prs, it is difficult to write mdx that’s robust to all these.
This is really interesting. On the one hand, it’s an easy thing to modify the Makefiles in the packages I develop, to not run mdx tests when invoked via opam. On the other hand … and in this I’m going to put a big, big caveat here, that I’m not a maintainer, so I don’t see the pain mdx causes you all. I could be very, very wrong about what I’m about to write.
First, you’re absolutely right that mdx output can be and is mercurial. Some examples (of which you’re very well aware, but I list them to show that I’ve dealt with them):
- output of the OCaml typechecker can change from version-to-version.
- filenames, hostnames, timestamps
- irrelevant error-messages that might or might not show up on other platforms
My attempt to address these (and other) problems is to use MDX by:
- run MDX against an
.asciidoc (or .md) file
- take the
.corrected output file and run a script against it that cleans up many of the above list
- for particular packages, run further cleaners. This produces a
.corrected.CLEANED file
- only then compare that file against the original.
I use Make, so this is embodied in rules :
- first a standard script (“clean-ocaml-mdx-output”) to clean:
$s =~ s,.*OCaml version.*,,g ;
$s =~ s,.*#help.*,,g ;
$s =~ s,.*Command line:.*\n,,g ;
$s =~ s,.*: added to search path.*\n,,g ;
$s =~ s,.*: loaded.*\n,,g ;
$s =~ s,.*Cannot read directory.*stublibs.*\n,,g ;
$s =~ s,.*Interface.*occurs in several directories.*\n,,g ;
$s =~ s,#<\|(?:[^\|]|\|[^>])*\|>\n?,,gs ;
That script:
(a) nukes version-numbers, various noise, commandlines output, paths, and superfluous error-messages
(b) sometimes error-messages produce -significant- diagnostic output in addition to the text we would want to match against for the test. The last line removes text of the form #<|....|> and the idea is, when I output large texts in error-messages, I try to wrapper it with these eyecatchers, so I can nuke that output before comparing.
(c) NOTE: one thing I haven’t dealt with, is stack tracebacks. I might need to figure out how to nuke them systematically, but they don’t seem to show up (yet).
But (as you know well) the above script isn’t enough. For example, in some OCaml versions the typechecker unfolds a type-abbreviation, and that means the output in the toplevel can vary. So in one case, I added:
pa_ppx-error-handling.asciidoc.corrected.CLEANED: pa_ppx-error-handling.asciidoc.corrected
$(TOP)/tools/clean-ocaml-mdx-output $< > $@.NEW && mv $@.NEW $@
perl -p -i -e 's|(.*migrate_z1.*)int \* bool,(.*)|$${1}z1,$${2}|' $@
This was to deal with a case where a type-signature of a member of a record contained int * (int * bool) where it needed to be int * z1 (z1 was of course an abbreviation for int * bool). This behaviour change showed up between OCaml versions (5.3, 5.4, IIRC, but I might be getting the version-numbers wrong).