Skip to content

test(session): count only sessions that garbage collection cannot remove - #34

Merged
knittingcode merged 2 commits into
mainfrom
fix/fcrm-auto4-fpm-session-test
Oct 25, 2026
Merged

knittingcode merged 2 commits into
mainfrom
fix/fcrm-auto4-fpm-session-test

Conversation

@knittingcode

@knittingcode knittingcode commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

Makes three integration tests independent of session garbage collection. FpmSessionTest::testStatelessRoutesNeverTouchTheSession failed once locally with Failed asserting that 108 is identical to 109 and passed on rerun. AuthenticationTest (3 tests) and AuditTrailTest (1 test) have the same defect. Only test code changes.

Motivation and technical context

The tests compared SELECT count(*) FROM sessions (the whole table) before and after some requests. Every request that starts a session runs the session garbage collection with probability 1/100 (gc_probability: 1, gc_divisor: 100 in config/packages/session.yaml). Garbage collection deletes every row whose expiry (sess_lifetime) has passed, including rows that earlier tests left behind. If it ran during a test, the count dropped by one even though the code under test wrote and deleted nothing.

  • In FpmSessionTest, the last request (GET /api/_test/session, "reading an empty session starts it") starts a session, so garbage collection can run there.
  • In AuthenticationTest and AuditTrailTest, the login requests start sessions.

Implementation

  • New tests/Support/Session/SessionRows. snapshot() sets a horizon of now + 600 s, and count() counts only rows with sess_lifetime >= horizon:
    • Garbage collection only deletes rows whose expiry is already in the past, so it cannot delete these rows while a test runs (tests take far less than 600 s).
    • Every row written during the test expires at now + 1800 s, so it is still counted. That lifetime is asserted by FpmSessionTest and SessionAndCacheConfigurationTest. A route that wrongly stores a session therefore still fails the assertion.
  • The three tests use the helper instead of their own private sessionCount(). Assertions and messages are unchanged.

Testing performed

All runs used a disposable Compose test stack (compose.test.yaml, project flowcrm-b4fpm, removed afterwards).

  1. Reproduction (temporary edits, not committed): gc_probability: 100 and an expired row planted before the first count. The old test failed at the last assertion (FpmSessionTest.php:95) with Failed asserting that 1 is identical to 2. This is the same off-by-one as the original 108 vs 109.
  2. Fix under the same forced conditions: the 5 affected tests (--filter on the five names), 5 runs in a row: OK (5 tests, 110 assertions) each time.
  3. Mutation (temporary): a non-expiring row inserted between the two counts, as a stateless route that stored a session would do. The fixed test failed with Failed asserting that 2 is identical to 1. (line 92), so the assertion still catches a stored session.
  4. Final code, real configuration:
    • Full integration suite: OK (274 tests, 2379 assertions).
    • FpmSessionTest alone, 3 runs: OK (17 tests, 228 assertions) each time.
  5. Backend gate (check-be):
    • Unit: OK (145 tests, 416 assertions).
    • PHPStan: [OK] No errors.
    • PHP CS Fixer: Found 0 of 172 files that can be fixed.
    • deptrac: Errors 0.
    • Architecture: OK (23 tests, 24 assertions).
  6. CI: run 40193116699 on d844b90 passed (Repository guard and Dev environment).

Security considerations

Only test code changes. The tests still fail when a stateless route, a failed login, a 401 or a login whose audit event fails stores a session (mutation check above). No assertion was removed or loosened beyond excluding rows that garbage collection may delete during the test.

Interaction with other PRs

Known limitations

  • The helper assumes that tests take less than 600 s and that the idle lifetime stays above 600 s (currently 1800 s, asserted elsewhere).
  • If someone lowers gc_maxlifetime below 600 s, SessionAndCacheConfigurationTest fails first.

FpmSessionTest::testStatelessRoutesNeverTouchTheSession failed once with
"108 is identical to 109": it compares count(*) of the whole sessions
table before and after requests, and its last request starts a session,
which runs the session garbage collection with a probability of 1/100.
That deletes every expired row, including rows earlier tests left
behind, so the count drops although the code under test changed nothing.
AuthenticationTest and AuditTrailTest compare the same global count
around requests that start a session (logins) and share the defect.

SessionRows fixes a horizon (now + 600 s) when a test takes its
snapshot and counts only rows that expire at or after it: garbage
collection cannot delete them during the test, and every row written in
the test (expiry now + 1800 s) is still counted, so a session stored by
the code under test still fails the assertion.
@knittingcode
knittingcode merged commit f891298 into main Oct 25, 2026
2 checks passed
@knittingcode
knittingcode deleted the fix/fcrm-auto4-fpm-session-test branch October 25, 2026 17:45
knittingcode added a commit that referenced this pull request Oct 25, 2026
tests/devenv/unit.sh keeps both new blocks: main's U-25 (login check of the stack suite) and this branch's U-26 (image removal by name).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant