urls & post_smoke¶
The two HTTP-level checks. Both spin up the Django test client with
force_login, both wrap requests in override_settings(ALLOWED_HOSTS=…)
so testserver is always accepted, both fail CRITICAL on HTTP 5xx.
They differ on method: urls only hits GET, post_smoke submits POST
payloads it generates from each view's form_class.
urls¶
Crawls urlpatterns depth-first, skips routes with URL kwargs (<int:pk>,
<uuid:id>, …), and probes the rest under every role configured:
[tool.django-doctor.urls]
roles = ["anonymous", "authenticated", "staff", "superuser"]
skip = ["admin:*", "djdt:*", "rp-initiated-logout"]
timeout = 10
Findings:
urls.get.5xx— HTTP 500+ returned.urls.get.exception— view raised before returning a response.
Creating the probe users¶
urls creates three users if they don't exist: doctor_user,
doctor_staff, doctor_superuser. On production snapshots you want to
point at a dev database — user rows (with generated passwords) do persist.
post_smoke¶
Discovers every CreateView / UpdateView reachable without URL kwargs,
extracts the form_class (or falls back to modelform_factory(model,
fields=fields)), auto-generates a minimal valid payload via
make_form_fixture, and submits it.
Safety¶
Every request runs inside transaction.atomic() + savepoint_rollback.
Even when the view reaches .save() and commits would happen, the
savepoint is rolled back afterwards, so the database is not mutated.
You still want to point this at a dev database — it writes a transient
superuser (doctor_post_smoke) and some views may trigger external side
effects (file uploads to S3, email sends, webhook calls) that the
savepoint doesn't reach.
Skip list¶
Findings¶
post_smoke.5xx— HTTP 500+ after the POST.post_smoke.exception— view raised Python exception.post_smoke.fixture_error(WARNING) — could not build a payload.post_smoke.partial_fixture(INFO) — required field could not be auto-filled (FileField, emptyModelChoicequeryset, …).post_smoke.stale_db.create(since 0.9) —CreateViewreturned 2xx/3xx butModel.objects.count()did not increase. The view reports success while silently dropping the submission. Common causes: a signal raised and was swallowed by outer middleware,form_valid()forgot to callsuper(), or an atomic wrapper rolled back.post_smoke.stale_db.update(since 0.9) —UpdateViewreturned 2xx/3xx but the target row did not reflect the POSTed values. The runtime twin of the staticupdate_fields.drops_computedcheck — catches cases static analysis can't resolve (dynamic receivers, helper-function indirection, …).
Real bug this caught on altiusone¶
[post_smoke:post_smoke.exception] operation-create (OperationTVACreateView)
POST raised IntegrityError: null value in column "montant_ttc" of
relation "operations_tva" violates not-null constraint
Root cause: OperationTVAForm.clean() assigned cleaned_data["montant_ttc"]
but the key wasn't in Meta.fields. Django silently dropped it.