Test that duplicate requests create one row
Send one request three times in a zriz pipeline, then count the rows in the database. One row proves that a retry makes no duplicate.
The problem
A client sends a request again after a timeout, or a user clicks two times. If the API stores each copy, the database gets duplicate rows. The status code does not show this: only the database does.
The test
The example is a shop API with a MySQL database. A second sign-up with one e-mail must get 409.
Start from a project that zz init made: the quick start gives the commands. Add the action register, the database value, and the database resource. The connection string stays on your machine, because SHOP_DB is in sensitive.
.zriz/resources/target.json:
{
"type": "http",
"description": "Your app under test",
"base-url": "${env.TARGET_URL}",
"headers": { "Content-Type": "application/json" },
"actions": {
"check": { "method": "GET", "path": "/api/health" },
"register": { "method": "POST", "path": "/api/auth/register" }
}
}
.zriz/environments/local.json:
{
"values": {
"TARGET_URL": "http://localhost:9080",
"SHOP_DB": "user:pass@tcp(localhost:3306)/shop"
},
"sensitive": ["SHOP_DB"]
}
.zriz/resources/shopdb.json:
{
"type": "sql",
"connection": "${env.SHOP_DB}",
"read-only": true,
"actions": {
"users-by-email": { "query": "SELECT id FROM users WHERE email = ${ctx.email}" }
}
}
.zriz/pipelines/register-three-times.json:
{
"description": "Three same sign-ups make one row",
"steps": [
{ "set": { "email": "u-${gen.uuid}@test.com" } },
{
"call": "target/register",
"body": { "email": "${ctx.email}", "password": "secret123", "name": "Ann" },
"expect": [["status", "==", 201]]
},
{
"for": { "each": "attempt", "in": [2, 3] },
"steps": [
{
"call": "target/register",
"body": { "email": "${ctx.email}", "password": "secret123", "name": "Ann" },
"expect": [["status", "==", 409], ["body.error", "==", "email already registered"]]
}
]
},
{
"call": "shopdb/users-by-email",
"expect": [["row-count", "==", 1]]
}
]
}
Run it
zz run register-three-times
"status":"pass"
What it proves
status == 201, then409two times: the API accepts the first request and refuses each copy.row-count == 1: the database has one row after three requests. This check finds a duplicate that the status code hides."read-only": true: the query of the test cannot write.
Note: An API with an idempotency key answers the copy with the first result, not with
409. Then expect the same status and the same id three times. The row check stays the same.
Next
- Test that a failed request writes no row
- Test an API call and the database row gives each step for your own database.
- Create a read-only Postgres user