{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/nimbusxr/axx/main/schemas/v0/axx.schema.json", "$defs": { "Active": { "properties": { "enabled": { "type": "boolean" }, "onNoTags": { "type": "string", "enum": [ "fallback", "error" ], "description": "OnNoTags decides what happens when the selected scenarios have no tags:\n\"fallback\" (start all enabled services, default) or \"error\"." } }, "additionalProperties": false, "type": "object", "description": "Active configures tag-based application startup." }, "Command": { "oneOf": [ { "type": "string", "description": "command line, split into words without a shell unless shell: true" }, { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "argv" } ] }, "CommandHook": { "oneOf": [ { "required": [ "before" ] }, { "required": [ "after" ] } ], "properties": { "before": { "type": "string", "minLength": 1, "description": "Before names the axx command it runs before, by its words after axx:\nfixtures generate. When it fails, that command does not run." }, "after": { "type": "string", "minLength": 1, "description": "After names the axx command it runs after, whether that command\nsucceeded or failed: AXX_COMMAND_FAILED is true or false. When it fails,\na command that succeeded fails." }, "command": { "$ref": "#/$defs/Command", "description": "Command is what it runs: a string (split like a shell word list,\nwithout a shell) or an argv list. Set shell: true to run it through the\nshell." }, "shell": { "type": "boolean", "description": "Shell runs command through /bin/sh -c (cmd /C on Windows)." } }, "additionalProperties": false, "type": "object", "required": [ "command" ], "description": "CommandHook runs a command before or after one of axx's commands, from the directory of axx.yaml." }, "Duration": { "oneOf": [ { "type": "string", "pattern": "^\\s*([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+\\s*$", "examples": [ "30s", "1m30s", "250ms" ] }, { "type": "number", "minimum": 0, "description": "seconds" } ] }, "FixtureConformance": { "properties": { "name": { "type": "string", "description": "Name is shown in check output." }, "filePatterns": { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "FilePatterns are globs (relative to baseDir) of the files to validate." }, "schemaType": { "type": "string", "description": "SchemaType is the family whose oracle validates the files: avro,\njson, yaml, xml, protobuf or dataset.", "examples": [ "avro", "json", "yaml", "xml", "protobuf", "dataset" ] }, "schemaRef": { "type": "string", "description": "SchemaRef is the schema, relative to baseDir (unlike factory.schema,\nwhich is relative to the factory file)." } }, "additionalProperties": false, "type": "object", "required": [ "name", "filePatterns", "schemaType", "schemaRef" ], "description": "FixtureConformance validates matched files against a schema." }, "FixtureLint": { "properties": { "emit": { "type": "boolean", "description": "Emit writes one cross-file-unique lint rule per declared identity.\nDefault: true." }, "output": { "type": "string", "description": "Output is the generated rules file, relative to baseDir. Default:\naxx-lint.generated.yaml. Wire it in with lint.include." } }, "additionalProperties": false, "type": "object", "description": "FixtureLint configures the generated lint rules." }, "FixtureOutput": { "properties": { "ignored": { "type": "boolean", "description": "Ignored makes outputs gitignored derivations instead of committed\nfiles: the tool maintains exact .gitignore entries and `axx fixtures\ngenerate` materializes them. Default: false." } }, "additionalProperties": false, "type": "object", "description": "FixtureOutput holds output defaults." }, "Fixtures": { "properties": { "baseDir": { "type": "string", "description": "BaseDir is the resource root every fixtures path resolves against,\nrelative to axx.yaml. Default: the directory of axx.yaml." }, "factories": { "items": { "type": "string" }, "type": "array", "description": "Factories are globs (relative to baseDir) locating factory specs.\nDefault: [\"**.factory.yaml\"]." }, "sources": { "items": { "type": "string" }, "type": "array", "description": "Sources are additional roots, relative to baseDir (\"../\" reaches\noutside it), walked for factory, prototype and fixture sources exactly\nlike baseDir, so fixtures can sit next to generated files that live\nelsewhere (a compose-mounted WireMock directory, say). Roots must\nexist and be disjoint from baseDir and each other." }, "conformance": { "items": { "$ref": "#/$defs/FixtureConformance" }, "type": "array", "description": "Conformance rules validate files no factory manages through a\nfamily's schema oracle." }, "lint": { "$ref": "#/$defs/FixtureLint", "description": "Lint configures the lint rules generated from identity declarations." }, "output": { "$ref": "#/$defs/FixtureOutput", "description": "Output holds module-wide output defaults; factories override them\nwith factory.output." } }, "additionalProperties": false, "type": "object", "description": "Fixtures configures `axx fixtures`, the fixture factory: *.factory.yaml, *.fixture.yaml and *.prototype.yaml sources expanded into schema-governed fixture files, with the ownership manifest, drift and conformance checks." }, "Hooks": { "properties": { "commands": { "items": { "$ref": "#/$defs/CommandHook" }, "type": "array", "description": "Commands run before or after axx's commands, like `axx fixtures\ngenerate`: a schema to write before fixtures are made from it, a report\nto send after a run." } }, "additionalProperties": false, "type": "object", "description": "Hooks run the project's own commands around axx's, by what they run around." }, "Lint": { "properties": { "include": { "$ref": "#/$defs/StringList", "description": "Include lists rule files merged into this section (for example the\naxx-lint.generated.yaml written by `axx fixtures generate`), resolved\nrelative to the including file. Included files contribute rules and\nfurther includes only; they must not have a config block." }, "config": { "$ref": "#/$defs/LintConfig", "description": "Config holds the settings shared by every rule." }, "rules": { "items": { "$ref": "#/$defs/LintRule" }, "type": "array", "description": "Rules are the isolation rules, run in order (included rules follow)." } }, "additionalProperties": false, "type": "object", "description": "Lint configures `axx lint`: test-data isolation rules." }, "LintConfig": { "properties": { "baseDir": { "type": "string", "description": "BaseDir is the directory file patterns are resolved against, relative\nto axx.yaml. Default: the directory of axx.yaml." }, "mode": { "type": "string", "enum": [ "error", "warn" ], "description": "Mode is \"error\" (violations make `axx lint` exit 3, default) or \"warn\"\n(violations are reported but do not fail, a scenario's second When or Then\nincluded)." }, "maxFileSize": { "type": "integer", "minimum": 1, "description": "MaxFileSize skips files larger than this many bytes, with a warning.\nDefault: 5242880 (5 MB)." }, "maxReportedValues": { "type": "integer", "minimum": 1, "description": "MaxReportedValues is how many duplicate values the human output lists\nper rule before truncating. Default: 3. Machine formats list all." }, "maxReportedLocations": { "type": "integer", "minimum": 1, "description": "MaxReportedLocations is how many locations the human output lists per\nduplicate value before truncating. Default: 5. Machine formats list all." } }, "additionalProperties": false, "type": "object", "description": "LintConfig holds the settings shared by every lint rule." }, "LintRule": { "properties": { "name": { "type": "string", "description": "Name identifies the rule in reports." }, "description": { "type": "string", "description": "Description says why the values must be unique; shown with violations." }, "filePatterns": { "$ref": "#/$defs/StringList", "description": "FilePatterns are glob patterns (Java glob syntax: *, **, ?, [abc],\n{a,b}) selecting the files to scan, relative to baseDir. The part\nbefore the first wildcard is a directory (it may start with ../); the\nrest is matched against the end of each file path below it, so\n\"seeds/*.yaml\" also finds YAML files in subdirectories of seeds. A\npattern that ends in \"/\" matches folders, and all the files below\neach folder it matches count as one file: a scenario whose data spans\nseveral files keeps them in a folder of its own (\"seeds/*/\"), whose\nfiles may share values that no other file may." }, "excludePatterns": { "$ref": "#/$defs/StringList", "description": "ExcludePatterns are glob patterns removing files from the match set,\nmatched against the whole path relative to baseDir; ** crosses\ndirectories, e.g. \"**.fixture.yaml\"." }, "type": { "type": "string", "enum": [ "regex", "jsonpath" ], "description": "Type is \"regex\" (default: extract values with regex) or \"jsonpath\"\n(read each file, by its extension, as JSON, YAML, XML or CSV, and\nextract the values at jsonPath)." }, "regex": { "type": "string", "description": "Regex is a Java regular expression, applied in MULTILINE mode (^ and $\nmatch at line boundaries). Each match contributes the text of its\nfirst participating capture group." }, "jsonPath": { "type": "string", "description": "JSONPath selects the values of a jsonpath rule, e.g. \"order.id\",\n\"payments[*].id\" or \"$.items[0].sku\" (exact field paths with array\nindexes or [*]); other JSONPath expressions (\"$..id\", filters) are\nevaluated like Jayway JsonPath. Only scalar values count. A seed's rows\nread alike in YAML, flat XML (\u003cdataset\u003e) and CSV: \"$['public.closures'][*]['id']\";\nin other XML, attributes are \"@name\" fields (\"line[*].@sku\") and an\nelement with only text is a value." }, "validation": { "type": "string", "enum": [ "global-unique", "file-unique", "cross-file-unique" ], "description": "Validation is \"global-unique\" (default: a value may occur once),\n\"file-unique\" (no repeats within a file; files may share values) or\n\"cross-file-unique\" (repeats within one file are fine; no two files\nmay share a value). A folder a folder pattern matches counts as one\nfile." }, "mode": { "type": "string", "enum": [ "error", "warn" ], "description": "Mode overrides config.mode for this rule: \"error\" or \"warn\"." }, "ignoreValues": { "$ref": "#/$defs/ScalarList", "description": "IgnoreValues are values never reported (intentionally shared constants)." } }, "additionalProperties": false, "type": "object", "required": [ "name", "filePatterns" ], "description": "LintRule is one test-data isolation rule." }, "OpenAPI": { "properties": { "levels": { "additionalProperties": { "type": "string" }, "type": "object" } }, "additionalProperties": false, "type": "object", "description": "OpenAPI holds default validation levels, keyed by validation message key (e.g." }, "Reporter": { "oneOf": [ { "type": "string", "enum": [ "pretty", "progress", "compact", "junit", "messages", "cucumber-json", "html", "agent", "teamcity" ] }, { "properties": { "pretty": { "type": "string", "description": "output file" }, "progress": { "type": "string", "description": "output file" }, "compact": { "type": "string", "description": "output file" }, "junit": { "type": "string", "description": "output file" }, "messages": { "type": "string", "description": "output file" }, "cucumber-json": { "type": "string", "description": "output file" }, "html": { "type": "string", "description": "output file" }, "agent": { "type": "string", "description": "output file" }, "teamcity": { "type": "string", "description": "output file" } }, "additionalProperties": false, "type": "object", "maxProperties": 1, "minProperties": 1 } ] }, "Run": { "properties": { "paths": { "items": { "type": "string" }, "type": "array", "description": "Paths are feature files or directories. Default: [\"features\"]." }, "tags": { "type": "string", "description": "Tags is a default tag expression, e.g. \"not @wip\". It narrows every run,\nthe files and directories named on the command line included; a scenario\npicked by its line (features/x.feature:14) runs whatever its tags." }, "uses": { "items": { "type": "string" }, "type": "array", "description": "Uses keeps the scenarios that use a step of one of these packs, like\n[mobile-ios] for the scenarios that drive an iOS app: a profile per\nplatform, with no tags. Like tags, it narrows every run but a scenario\npicked by its line." }, "workers": { "$ref": "#/$defs/Workers", "description": "Workers is the number of scenarios run in parallel: a number or \"auto\"\n(number of CPUs). Default: auto." }, "exclusive": { "items": { "type": "string" }, "type": "array", "description": "Exclusive lists tags whose scenarios run alone, after the parallel phase." }, "exclusiveUses": { "items": { "type": "string" }, "type": "array", "description": "ExclusiveUses runs alone, after the parallel phase, the scenarios that use\na step of one of these packs, or one of these steps: its ID, or the start\nof its ID, like [faults, sql.trigger]. A way to have them run alone with no\ntags, which nothing turns on for you." }, "order": { "type": "string", "description": "Order is \"defined\" (default) or \"random[:seed]\"." }, "timeouts": { "$ref": "#/$defs/Timeouts" }, "watch": { "type": "boolean", "description": "Watch shows what the scenarios do, as they do it: the packs that can\nshow it on screen do (browsers and devices in their windows). Same as\naxx run --watch." }, "slowdown": { "$ref": "#/$defs/Duration", "description": "Slowdown pauses after each action of a watched run (a click, a tap, a\ntyped field), so a person can follow it, e.g. \"500ms\". Same as\naxx run --slowdown." }, "reporters": { "items": { "$ref": "#/$defs/Reporter" }, "type": "array", "description": "Reporters, e.g. [\"pretty\", {\"junit\": \"build/axx/junit.xml\"}]." } }, "additionalProperties": false, "type": "object", "description": "Run controls execution." }, "ScalarList": { "items": { "oneOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" } ] }, "type": "array" }, "Services": { "additionalProperties": { "properties": { "enabled": { "type": "boolean", "description": "Enabled defaults to true." }, "dir": { "type": "string", "description": "Dir is the working directory, relative to axx.yaml." }, "command": { "oneOf": [ { "type": "string", "description": "command line, split into words without a shell unless shell: true" }, { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "argv" } ], "description": "Command starts the service: a string (split like a shell word list, without\na shell) or an argv list. Set shell: true to run it through the shell.\nIt can tell axx properties, like the ports Docker gave its containers:\nlines name=value in the file AXX_PROPERTIES names, which scenarios,\nreadiness checks and the services that depend on it read as\n${sys:name}. Its ${…} references, and those of env and cleanup, are\nfilled in as the service starts, with what the services it depends on\ntold." }, "shell": { "type": "boolean", "description": "Shell runs command and cleanup through /bin/sh -c (cmd /C on Windows)." }, "env": { "additionalProperties": { "type": "string" }, "type": "object", "description": "Env are variables the command gets, beside axx's own environment." }, "dependsOn": { "items": { "type": "string" }, "type": "array", "description": "DependsOn names services that must be ready first: what they tell axx\nfills in this one's command, env and cleanup." }, "ready": { "properties": { "http": { "properties": { "url": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] } }, "additionalProperties": false, "type": "object", "required": [ "url" ] }, "tcp": { "type": "string", "description": "TCP is a host:port that must accept connections." }, "exec": { "oneOf": [ { "type": "string", "description": "command line, split into words without a shell unless shell: true" }, { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "argv" } ], "description": "Exec is a command that must exit 0." }, "log": { "type": "string", "description": "Log is a regular expression matched against the service's output." }, "timeout": { "oneOf": [ { "type": "string", "pattern": "^\\s*([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+\\s*$", "examples": [ "30s", "1m30s", "250ms" ] }, { "type": "number", "minimum": 0, "description": "seconds" } ], "description": "Timeout for the service to become ready. Default: 60s." }, "interval": { "oneOf": [ { "type": "string", "pattern": "^\\s*([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+\\s*$", "examples": [ "30s", "1m30s", "250ms" ] }, { "type": "number", "minimum": 0, "description": "seconds" } ], "description": "Interval between checks. Default: 1s." } }, "additionalProperties": false, "type": "object" }, "stop": { "properties": { "signal": { "type": "string", "enum": [ "SIGTERM", "SIGINT" ], "description": "Signal sent first: SIGTERM (default) or SIGINT." }, "grace": { "oneOf": [ { "type": "string", "pattern": "^\\s*([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+\\s*$", "examples": [ "30s", "1m30s", "250ms" ] }, { "type": "number", "minimum": 0, "description": "seconds" } ], "description": "Grace period before the process group is killed. Default: 10s." } }, "additionalProperties": false, "type": "object" }, "cleanup": { "oneOf": [ { "type": "string", "description": "command line, split into words without a shell unless shell: true" }, { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "argv" } ], "description": "Cleanup runs after the service stops, even if it crashed." }, "active": { "properties": { "tags": { "items": { "type": "string" }, "type": "array", "description": "Tags start the service for the scenarios that have one of them." }, "uses": { "items": { "type": "string" }, "type": "array", "description": "Uses starts the service for the scenarios that use a step of one of these\npacks, like [mobile-android]: no tag needed." } }, "additionalProperties": false, "type": "object" }, "debug": { "properties": { "command": { "oneOf": [ { "type": "string", "description": "command line, split into words without a shell unless shell: true" }, { "items": { "type": "string" }, "type": "array", "minItems": 1, "description": "argv" } ], "description": "Command replaces the normal command in debug mode." }, "debugger": { "properties": { "type": { "type": "string", "enum": [ "java", "go", "nodejs", "python" ] }, "port": { "type": "integer" }, "host": { "type": "string" }, "module": { "type": "string" }, "mode": { "type": "string", "enum": [ "ide-listens", "app-listens" ], "description": "Mode is \"ide-listens\" (the IDE listens and the service connects, e.g. JDWP\nserver=n; default for java) or \"app-listens\" (delve, --inspect, debugpy)." } }, "additionalProperties": false, "type": "object", "required": [ "port" ] }, "onUnavailable": { "type": "string", "enum": [ "fail", "fallback", "retry" ], "description": "OnUnavailable decides what happens when the debugger is not listening:\nfail, fallback (run the normal command) or retry (default)." }, "retry": { "properties": { "attempts": { "type": "integer" }, "delay": { "oneOf": [ { "type": "string", "pattern": "^\\s*([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+\\s*$", "examples": [ "30s", "1m30s", "250ms" ] }, { "type": "number", "minimum": 0, "description": "seconds" } ] } }, "additionalProperties": false, "type": "object" } }, "additionalProperties": false, "type": "object" } }, "additionalProperties": false, "type": "object", "required": [ "command" ], "description": "Service is an application or piece of infrastructure managed by axx." }, "type": "object" }, "StringList": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "Timeouts": { "properties": { "step": { "$ref": "#/$defs/Duration" }, "scenario": { "$ref": "#/$defs/Duration" }, "hook": { "$ref": "#/$defs/Duration" } }, "additionalProperties": false, "type": "object", "description": "Timeouts bound steps, scenarios and hooks." }, "Workers": { "oneOf": [ { "type": "integer", "minimum": 1 }, { "type": "string", "enum": [ "auto" ] } ] } }, "properties": { "version": { "type": "integer", "enum": [ 1 ], "description": "Schema version of this file. Currently 1." }, "axx": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?$", "description": "Axx is the version of axx this project runs on, exactly. Whichever axx is\ninstalled downloads that release once and hands over to it, so that everyone\nand CI run the same one. `axx upgrade` moves it. Without it, a project runs\non the installed axx." }, "run": { "$ref": "#/$defs/Run", "description": "Run controls which features run and how." }, "resources": { "items": { "type": "string" }, "type": "array", "description": "Resources are directories that relative resource paths in steps (seed\nfiles, schemas, payloads) resolve against, in order, once the feature\nfile's own directory has not got the file. The directory of axx.yaml is\nalways searched last." }, "properties": { "additionalProperties": { "type": "string" }, "type": "object", "description": "Properties back ${sys:name} references. `-D name=value` overrides them,\nand they override what services write to the file AXX_PROPERTIES\nnames: a value you set always wins." }, "openapi": { "$ref": "#/$defs/OpenAPI", "description": "OpenAPI holds default OpenAPI validation settings for REST services." }, "active": { "$ref": "#/$defs/Active", "description": "Active starts only the applications needed by the selected scenarios." }, "services": { "$ref": "#/$defs/Services", "description": "Services are the applications under test (and their infrastructure),\nstarted before scenarios run and stopped afterwards, in declaration order." }, "packs": { "additionalProperties": true, "type": "object", "description": "Packs holds pack settings keyed by pack name." }, "hooks": { "$ref": "#/$defs/Hooks", "description": "Hooks run the project's own commands around axx's, by what they run\naround." }, "lint": { "$ref": "#/$defs/Lint", "description": "Lint configures `axx lint`: test-data isolation rules that keep values\nsuch as seed ids unique so scenarios can run in parallel." }, "fixtures": { "$ref": "#/$defs/Fixtures", "description": "Fixtures configures `axx fixtures` (fixture factories)." }, "profiles": { "additionalProperties": true, "type": "object", "description": "Profiles are named overlays selected with --profile or AXX_PROFILE." } }, "additionalProperties": false, "type": "object", "title": "axx.yaml", "description": "Configuration for axx, the acceptance testing framework that verifies running software black-box (https://axx.nimbusxr.us)." }