Skip to content

Property-based coverage for the structured logging hook (cuprum/adapters/logging_adapter.py) #252

Description

@leynos

Overview

Add property-based coverage for the structured logging hook in
cuprum/adapters/logging_adapter.py, closing the last gap left by issue #78.

Background

Issue #78 is titled "Hypothesis stateful tests for metrics/tracing/logging
hooks", but its body scopes the work to cuprum/adapters/metrics_adapter.py.
Taking the title at its word, the three adapters now stand as follows:

Adapter Randomised event-sequence coverage
tracing_adapter.py cuprum/unittests/test_tracing_span_stateful.py (pre-existing)
metrics_adapter.py cuprum/unittests/test_metrics_adapter_stateful.py (added in #247)
logging_adapter.py none

So only the logging hook is outstanding.

Why a state machine is the wrong shape here

RuleBasedStateMachine earns its keep in the other two adapters because both
hold an active map keyed by ExecIdTracingHook._active_spans and the
metrics collector's in-flight state — and the interesting bugs are drain and
correlation bugs across interleaved sequences.

structured_logging_hook has no such state. It is a pure per-event function:
it maps a phase to a level, builds an extra mapping, formats a message, and
emits exactly one record. There is no map to drain and no cross-event
correlation to break, so a state machine would generate interleavings that
cannot distinguish any two implementations.

@given over generated ExecEvent values (and short sequences) is the shape
that actually tests the behaviour.

Proposed properties

  • One record per event. Every event emits exactly one LogRecord; no
    phase is silently dropped.
  • Level mapping is total. The level_map in logging_adapter.py:108
    covers every phase the event model can produce, and an unmapped phase falls
    back to the documented default rather than raising.
  • Field namespacing. Every attribute _build_extra attaches is
    cuprum_-prefixed, so records cannot collide with LogRecord's reserved
    attribute names — this is the failure mode that would surface as a
    KeyError at emit time deep in a user's logging configuration.
  • JSON round-trip. For any event, JsonLoggingFormatter.format produces
    a string that json.loads accepts, and _json_serializable leaves no value
    that json.dumps would reject.
  • Message formatting is total. _format_message produces a non-empty
    string for every phase, including events with absent optional fields.

Benefit

The JSON round-trip and field-namespacing properties are the valuable ones:
both fail only for specific event shapes that hand-written tests are unlikely
to enumerate, and both fail inside the user's logging stack rather than in
cuprum, which makes them expensive to diagnose in the field.

Cost trade-off

Low. The event strategies already exist in
cuprum/unittests/test_metrics_adapter_stateful.py and can be shared.

Recommended order

After the current property-test tranche lands. No production refactor is
needed first — unlike the metrics work, the logging reducers are already pure.


Raised from PR #247, which closes the
metrics portion of #78.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttestingTest coverage, test infrastructure, and verification tooling work.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions