|
| 1 | +# Absurd SQL 0.4.0 test parity |
| 2 | + |
| 3 | +## Purpose |
| 4 | + |
| 5 | +This document tracks high-signal test parity for the Rust SDK against the upstream Absurd `0.4.0` Python, TypeScript, and Go SDK suites. |
| 6 | + |
| 7 | +Coverage parity is not the goal. The goal is confidence in public Rust SDK behavior, durable workflow semantics, and intentional Rust deviations documented in `docs/parity/absurd-sql-0.4.0.md`. |
| 8 | + |
| 9 | +## Target |
| 10 | + |
| 11 | +- Absurd SQL tag: `0.4.0` |
| 12 | +- Absurd SQL commit: `05282a40c8dddc378acdc6933adc4c221583808a` |
| 13 | +- Rust crate version: `0.1.0` |
| 14 | +- Rust test suites: |
| 15 | + - unit tests in `src/**` |
| 16 | + - ignored database integration suite in `tests/integration.rs` |
| 17 | + |
| 18 | +## Scope |
| 19 | + |
| 20 | +Included: |
| 21 | + |
| 22 | +- public Rust SDK behavior |
| 23 | +- database-backed durable semantics surfaced through the SDK |
| 24 | +- failure, cancellation, retry, worker, event, checkpoint, and task-result invariants |
| 25 | +- Rust-specific diagnostics and intentional API decisions |
| 26 | + |
| 27 | +Excluded: |
| 28 | + |
| 29 | +- duplicate sync/async coverage from Python and TypeScript |
| 30 | +- language-specific decorator, contextvar, or global-context behavior |
| 31 | +- Go driver matrix tests |
| 32 | +- raw claim/execute APIs that Rust intentionally keeps internal |
| 33 | +- `absurdctl`, cron, SQL migration, partition maintenance, and storage-engine tests owned by upstream Absurd |
| 34 | +- exact traceback-string parity, which Rust intentionally does not implement |
| 35 | + |
| 36 | +## Test parity matrix |
| 37 | + |
| 38 | +| Area | Rust status | Existing Rust evidence | High-signal action | |
| 39 | +|---|---|---|---| |
| 40 | +| Absurd SQL `0.4.0` schema target | Covered | CI installs upstream SQL; DB integration suite runs against it | None | |
| 41 | +| Connection defaults | Partial | `Client::from_env*` exists; no direct Rust test for env precedence | Add unit tests for explicit URL, `ABSURD_DATABASE_URL`, `DATABASE_URL`, `PGDATABASE`, and localhost fallback | |
| 42 | +| Queue create, list, drop | Covered | `queue_create_list_drop_round_trip` | None | |
| 43 | +| Partitioned queue creation | Covered | `partitioned_queue_create_round_trip` | Optional partitioned idempotency smoke; not required now | |
| 44 | +| Queue policy get/set | Covered | `queue_policy_round_trip`; queue policy wire-key unit tests | None | |
| 45 | +| Typed task registration and spawn | Covered | `basic_typed_task_round_trip` | None | |
| 46 | +| Spawn options | Partial | `spawn_options_use_sql_wire_keys`; header and idempotency integration tests | Add max-attempt override/default persistence; reject unregistered spawn without queue; reject registered queue mismatch | |
| 47 | +| Spawn headers | Covered | `spawn_headers_are_available_to_task_context`; hook tests | None | |
| 48 | +| Idempotent spawn | Covered | `idempotent_spawn_creates_one_task_and_executes_once` | Optional different-key and queue-scope cases; not required now | |
| 49 | +| Retry without explicit strategy | Covered | `failed_task_retries_immediately_until_success` | None | |
| 50 | +| Fixed retry strategy | Covered | `fixed_retry_strategy_delays_next_attempt` | None | |
| 51 | +| Exponential retry strategy | Missing | wire shape exists through `RetryStrategy`, but no DB behavior test | Add DB integration test using `absurd.fake_now` to validate increasing delay and max cap | |
| 52 | +| Explicit none retry strategy | Missing | `RetryStrategy::none()` exists; no DB behavior test | Add DB integration test that `kind: none` is persisted and requeues immediately when attempts remain | |
| 53 | +| Cancellation by max delay | Missing | wire serialization through `CancellationPolicy`; no DB behavior test | Add DB integration test where a delayed first claim cancels the task | |
| 54 | +| Cancellation by max duration | Missing | wire serialization through `CancellationPolicy`; no DB behavior test | Add DB integration test where retry after elapsed duration cancels the task | |
| 55 | +| Default task cancellation | Missing | `task_builder_sets_default_cancellation` only checks builder state | Add DB integration test proving task-level default cancellation is applied when spawn options omit cancellation | |
| 56 | +| Worker batch execution | Partial | `basic_typed_task_round_trip`; event batch tests | Add mixed success/failure batch test proving failure of one task does not prevent later claimed tasks from running | |
| 57 | +| Continuous worker lifecycle | Partial | `worker_close_waits_for_running_tasks` | Add concurrency-limit test for `start_worker` | |
| 58 | +| Worker error callback | Covered | `worker_on_error_reports_claim_failures`; `worker_on_error_reports_execution_failures`; unit callback tests | None | |
| 59 | +| Durable `TaskContext::step` checkpoint | Covered | `step_checkpoint_is_reused_after_retry`; `failed_step_is_not_checkpointed_and_reexecutes` | Add multistep retry test where only unfinished steps re-execute | |
| 60 | +| Decomposed steps | Partial | `decomposed_step_handle_reuses_completed_state_after_retry`; `failed_decomposed_step_is_not_checkpointed_and_reexecutes` | Add repeated `begin_step` / `complete_step` name numbering test | |
| 61 | +| Sleep / scheduled resume | Covered | `sleep_until_suspends_then_resumes_from_checkpoint` | None | |
| 62 | +| Event await/emit | Partial | `pre_emitted_event_is_available_to_late_waiter`; `emitted_event_wakes_all_waiters`; `event_timeout_can_be_caught_without_recreating_wait` | Add first-write-wins `emit_event` test | |
| 63 | +| Task result fetch/await | Partial | terminal fetch/await, failed/cancelled/missing, timeout, same-queue rejection, completed cross-queue await | Add cross-queue pending child wait; add checkpoint-survives-parent-retry-after-child-cleanup test | |
| 64 | +| Manual retry task | Covered | default, max-attempt override, spawn-new, missing-task, and non-failed-task tests | None | |
| 65 | +| Manual cancel task | Partial | pending cancel and terminal race tests | Add running cancel, sleeping cancel, completed/failed no-op, and missing-task error tests | |
| 66 | +| Cleanup tasks/events | Missing | No Rust integration test found; parity doc currently claims coverage | Add `Client::cleanup` / `cleanup_with_limit` integration test for terminal tasks and emitted events | |
| 67 | +| Hooks | Covered | before-spawn inject/preserve, wrap execution, and context access tests | None | |
| 68 | +| Failure payload shape | Covered | user error, invalid headers, task-result failure payload assertions | None | |
| 69 | +| Panic handling | Covered | `panic_failure_payload_records_diagnostic_shape` | None | |
| 70 | +| Raw task claim API | Not applicable | intentionally internal in Rust | Do not add public parity tests | |
| 71 | +| Sync client API | Not applicable | Rust SDK is intentionally async-only | Do not add | |
| 72 | +| Global/decorator task context | Not applicable | Rust uses explicit `TaskContext` | Do not add | |
| 73 | +| Logger injection | Not applicable | Rust uses `tracing` and `WorkerOptions::on_error` | Do not add | |
| 74 | +| Failure traceback strings | Not applicable | Rust asserts diagnostic payload with `traceback: null` | Do not chase upstream traceback-string tests | |
| 75 | + |
| 76 | +## Recommended implementation backlog |
| 77 | + |
| 78 | +### Required high-signal additions |
| 79 | + |
| 80 | +1. `cleanup_removes_terminal_tasks_and_events_by_ttl` |
| 81 | +2. `cancellation_policy_cancels_by_max_delay` |
| 82 | +3. `cancellation_policy_cancels_by_max_duration` |
| 83 | +4. `default_task_cancellation_is_applied` |
| 84 | +5. `exponential_retry_strategy_delays_attempts` |
| 85 | +6. `retry_strategy_none_requeues_immediately` |
| 86 | +7. `spawn_resolution_applies_defaults_overrides_and_rejects_queue_mismatches` |
| 87 | +8. `work_batch_handles_mixed_success_and_failure` |
| 88 | +9. `worker_respects_concurrency_limit` |
| 89 | +10. `event_emit_is_first_write_wins` |
| 90 | +11. `context_await_task_result_waits_for_pending_child_in_other_queue` |
| 91 | +12. `context_await_task_result_checkpoint_survives_parent_retry_after_child_cleanup` |
| 92 | +13. `manual_cancel_running_sleeping_terminal_and_missing_cases` |
| 93 | +14. `multi_step_only_reexecutes_uncompleted_steps` |
| 94 | +15. `repeated_decomposed_step_names_are_numbered` |
| 95 | +16. `connection_defaults_resolve_env_precedence` |
| 96 | + |
| 97 | +### Test design notes |
| 98 | + |
| 99 | +- Prefer one focused integration test per durable invariant. |
| 100 | +- Use `SET absurd.fake_now` where possible instead of real sleeps for retry and cancellation timing. |
| 101 | +- Keep optional permutation tests out unless they catch a distinct class of regression. |
| 102 | +- Keep language-specific upstream tests out of the Rust suite unless Rust exposes an equivalent public surface. |
| 103 | + |
| 104 | +## Validation commands |
| 105 | + |
| 106 | +```sh |
| 107 | +cargo fmt --all --check |
| 108 | +cargo clippy --all-targets --all-features -- -D warnings |
| 109 | +cargo test --all-targets --all-features |
| 110 | +ABSURD_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/absurd_test cargo test-db |
| 111 | +``` |
0 commit comments