Running acceptance tests¶
Info
Learn the concepts and fundamentals of acceptance tests in the Explanation page.
Acceptance tests are formal tests that verify if a system satisfies business requirements.
Included in this how-to guide are instructions on how to interact with
acceptance tests using the /v1/applications/{application_id}/experiments/acceptance
endpoints. Go the reference section to see all
the available parameters for each endpoint.
Create an acceptance test¶
An acceptance test requires metrics to determine the pass/fail criteria. Pass
the metrics field in the request payload as a list of
metric objects.
Each metric has the following attributes:
field: Field of the metric to measure (e.g.,"result.custom.unassigned").metric_type: Type of metric comparison. Allowed values:direct-comparison.params: A metric params object, with:operator: Comparison operator. Allowed values:eq,gt,ge,lt,le, andne.tolerance: Tolerance for the comparison, with:type: Type of tolerance. Allowed values:absolute, andrelative.value: Tolerance value (numeric).
statistic: Statistical method used to summarize the metric. Allowed values:min,max,mean,std,shifted_geometric_mean,p01,p05,p10,p25,p50,p75,p90,p95, andp99.
Consider the following example where a metric is defined stating that the mean
of the value must be equal between two instances, without any
tolerance.
{
"field": "value",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {"type": "absolute", "value": 0}
},
"statistic": "mean"
}
An acceptance test relies on an underlying batch experiment that shares the
same ID. Use the POST
/v1/applications/{application_id}/experiments/batch endpoint to
create it, specifying the instance_ids to compare and the input
set to test against. Afterwards, use the POST
/v1/applications/{application_id}/experiments/acceptance
endpoint, referencing that batch experiment's ID in the experiment_id field,
to create the acceptance test itself.
Here is an example that uses the metric defined above to create a new
acceptance test for an application, comparing the production and staging
instances. The data is loaded from an input set.
TEST_ID="acceptance-$(openssl rand -hex 4)"
curl -s -X POST "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/batch" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"id\": \"${TEST_ID}\", \"name\": \"${TEST_ID}\", \"input_set_id\": \"leaping-hares\", \"instance_ids\": [\"staging\", \"production\"]}" \
| jq '.'
curl -s -X POST "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/acceptance" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"id\": \"${TEST_ID}\", \"name\": \"${TEST_ID}\", \"experiment_id\": \"${TEST_ID}\", \"candidate\": {\"instance_id\": \"staging\"}, \"control\": {\"instance_id\": \"production\"}, \"metrics\": [{\"field\": \"value\", \"metric_type\": \"direct-comparison\", \"params\": {\"operator\": \"eq\", \"tolerance\": {\"type\": \"absolute\", \"value\": 0}}, \"statistic\": \"mean\"}]}" \
| jq '.'
{
"id": "acceptance-fe717ff5"
}
{
"id": "acceptance-fe717ff5",
"name": "acceptance-fe717ff5",
"description": "",
"app_id": "uncanny-rodent",
"experiment_id": "acceptance-fe717ff5",
"control": {
"instance_id": "production",
"version_id": "v0.0.2"
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2"
},
"metrics": [
{
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
}
],
"results_status": "",
"created_at": "2026-07-29T14:35:08.895232419Z",
"updated_at": "2026-07-29T14:35:08.895232419Z"
}
The call above will create a random ID, and use the same identifier for the
acceptance test's name. The name of the test is used as a human-readable
label. You can pass different values for the id and name fields in the
payload to specify a custom ID and name for the acceptance test. For example:
TEST_ID="dusty-acceptance-test"
curl -s -X POST "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/batch" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"id\": \"${TEST_ID}\", \"name\": \"Acceptance test for a dusty bunny\", \"input_set_id\": \"leaping-hares\", \"instance_ids\": [\"staging\", \"production\"]}" \
| jq '.'
curl -s -X POST "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/acceptance" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
-H "Content-Type: application/json" \
-d "{\"id\": \"${TEST_ID}\", \"name\": \"Acceptance test for a dusty bunny\", \"experiment_id\": \"${TEST_ID}\", \"candidate\": {\"instance_id\": \"staging\"}, \"control\": {\"instance_id\": \"production\"}, \"metrics\": [{\"field\": \"value\", \"metric_type\": \"direct-comparison\", \"params\": {\"operator\": \"eq\", \"tolerance\": {\"type\": \"absolute\", \"value\": 0}}, \"statistic\": \"mean\"}]}" \
| jq '.'
{
"id": "dusty-acceptance-test"
}
{
"id": "dusty-acceptance-test",
"name": "Acceptance test for a dusty bunny",
"description": "",
"app_id": "uncanny-rodent",
"experiment_id": "dusty-acceptance-test",
"control": {
"instance_id": "production",
"version_id": "v0.0.2"
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2"
},
"metrics": [
{
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
}
],
"results_status": "",
"created_at": "2026-07-29T14:35:51.560363497Z",
"updated_at": "2026-07-29T14:35:51.560363497Z"
}
Get an acceptance test¶
Info
The best way to view and interact with acceptance test results is in the Nextmv Console.
You can get the results using the GET
/v1/applications/{application_id}/experiments/acceptance/{acceptance_id}
endpoint. The response includes the results for the evaluated metrics once the
underlying batch experiment finishes running.
{
"id": "dusty-acceptance-test",
"name": "Acceptance test for a dusty bunny",
"description": "",
"app_id": "uncanny-rodent",
"experiment_id": "dusty-acceptance-test",
"control": {
"instance_id": "production",
"version_id": "v0.0.2"
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2"
},
"metrics": [
{
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
}
],
"created_at": "2026-07-29T14:35:51.560363497Z",
"updated_at": "2026-07-29T14:36:23.246843508Z",
"status": "completed",
"results": {
"passed": true,
"metric_results": [
{
"metric": {
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
},
"statistics": {
"control": {
"instance_id": "production",
"version_id": "v0.0.2",
"number_of_runs_total": 3,
"distribution_summary_statistics": {
"min": 1.23,
"max": 1.23,
"count": 3,
"mean": 1.23,
"std": 0,
"shifted_geometric_mean": 1.2300000000000022,
"shift_parameter": 10
},
"distribution_percentiles": {
"p01": 1.23,
"p05": 1.23,
"p10": 1.23,
"p25": 1.23,
"p50": 1.23,
"p75": 1.23,
"p90": 1.23,
"p95": 1.23,
"p99": 1.23
}
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2",
"number_of_runs_total": 3,
"distribution_summary_statistics": {
"min": 1.23,
"max": 1.23,
"count": 3,
"mean": 1.23,
"std": 0,
"shifted_geometric_mean": 1.2300000000000022,
"shift_parameter": 10
},
"distribution_percentiles": {
"p01": 1.23,
"p05": 1.23,
"p10": 1.23,
"p25": 1.23,
"p50": 1.23,
"p75": 1.23,
"p90": 1.23,
"p95": 1.23,
"p99": 1.23
}
}
},
"metric_pairs": {
"latest-RUM_rQEDg": [1.23, 1.23],
"latest-bdIl9QEDR": [1.23, 1.23],
"latest-pmN_9wEvg": [1.23, 1.23]
},
"passed": true
}
]
}
}
You can list all acceptance tests in the application using the GET
/v1/applications/{application_id}/experiments/acceptance
endpoint. This endpoint is paginated, so the snippet below always uses
pagination: it passes pagereturn=true to receive a next_page_token in the
response, and keeps requesting pages by passing that token back as
pagetoken until no token is returned.
ITEMS="[]"
PAGE_TOKEN=""
while :; do
RESPONSE=$(curl -s -G "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/acceptance" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
--data-urlencode "pagereturn=true" \
--data-urlencode "pagetoken=${PAGE_TOKEN}")
ITEMS=$(jq -n --argjson existing "$ITEMS" --argjson page "$(echo "$RESPONSE" | jq '.items')" '$existing + $page')
PAGE_TOKEN=$(echo "$RESPONSE" | jq -r '.next_page_token // empty')
[ -z "$PAGE_TOKEN" ] && break
done
echo "$ITEMS" | jq '.[:2]'
[
{
"id": "dusty-acceptance-test",
"name": "Acceptance test for a dusty bunny",
"description": "",
"app_id": "uncanny-rodent",
"experiment_id": "dusty-acceptance-test",
"control": {
"instance_id": "production",
"version_id": "v0.0.2"
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2"
},
"metrics": [
{
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
}
],
"results_status": "",
"created_at": "2026-07-29T14:35:51.560363497Z",
"updated_at": "2026-07-29T14:35:51.560363497Z"
},
{
"id": "acceptance-fe717ff5",
"name": "acceptance-fe717ff5",
"description": "",
"app_id": "uncanny-rodent",
"experiment_id": "acceptance-fe717ff5",
"control": {
"instance_id": "production",
"version_id": "v0.0.2"
},
"candidate": {
"instance_id": "staging",
"version_id": "v0.0.2"
},
"metrics": [
{
"field": "value",
"statistic": "mean",
"metric_type": "direct-comparison",
"params": {
"operator": "eq",
"tolerance": {
"type": "absolute",
"value": 0
}
}
}
],
"results_status": "",
"created_at": "2026-07-29T14:35:08.895232419Z",
"updated_at": "2026-07-29T14:35:08.895232419Z"
}
]
Update an acceptance test¶
You can update attributes of an acceptance test with the PATCH
/v1/applications/{application_id}/experiments/acceptance/{acceptance_id}
endpoint, such as its:
- Name
- Description
The endpoint returns the updated acceptance test. You cannot update the ID of an acceptance test.
curl -s -X PATCH "https://api.cloud.nextmv.io/v1/applications/uncanny-rodent/experiments/acceptance/dusty-acceptance-test" \
-H "Authorization: Bearer ${NEXTMV_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Acceptance Test Name", "description": "Updated description for the acceptance test"}' \
| jq '.'
Delete an acceptance test¶
Warning
Deleting an acceptance test is irreversible. All the data associated with the acceptance test will be permanently deleted.
Delete an acceptance test using the DELETE
/v1/applications/{application_id}/experiments/acceptance/{acceptance_id}
endpoint.