79 lines
3.6 KiB
Markdown
79 lines
3.6 KiB
Markdown
# PR#130: Repository Privacy Answer Kept and Renewed in Steps
|
|
|
|
> **WARNING:** This document describes only the change applied in this PR.
|
|
> It may already be outdated once the next PR is merged.
|
|
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
|
|
|
|
## The Problem
|
|
|
|
`RepositoryPrivacy.isPrivate` is above the Mutation-CRAP target of 15 in the nightly mutation build of 2026-10-07 and 2026-10-09:
|
|
|
|
| Method | Mutation-CRAP | Complexity | Killed / eligible |
|
|
|-------------------------------|--------------:|-----------:|------------------:|
|
|
| `RepositoryPrivacy.isPrivate` | 16.40 | 10 | 9 / 15 |
|
|
|
|
One method decided whether the cached answer still stands, asked the forge, warned about a silent forge and stored the new answer.
|
|
The tests never touched the exact moment an answer expires, and nothing checked that a silent forge is reported once and not on every retry.
|
|
|
|
## Non-Goals
|
|
|
|
- No change of the behaviour: the same answers, the same expiry times, the same warning.
|
|
|
|
## The Scenarios
|
|
|
|
### Feature: The privacy answer of a repository
|
|
|
|
#### Scenario#130.01: A cached answer expires at exactly its validity
|
|
|
|
So that a repository that changed its visibility is followed within the stated time, and not one poll later or earlier.
|
|
|
|
- **Given** the forge answered for a repository
|
|
- **When** one second less than the answer's validity has passed
|
|
- **Then** the cached answer is returned and the forge is not asked
|
|
- **When** the full validity has passed
|
|
- **Then** the forge is asked again
|
|
- The validity is `REFRESH_AFTER` (15 minutes) for a confirmed answer and `RETRY_UNKNOWN_AFTER` (1 minute) for a guess.
|
|
|
|
##### Verified by
|
|
|
|
- [RepositoryPrivacyUnitTest: a confirmed answer stands for exactly REFRESH_AFTER](../../src/test/kotlin/de/hoennig/werkator/server/RepositoryPrivacyUnitTest.kt)
|
|
- [RepositoryPrivacyUnitTest: a guess stands for exactly RETRY_UNKNOWN_AFTER](../../src/test/kotlin/de/hoennig/werkator/server/RepositoryPrivacyUnitTest.kt)
|
|
|
|
#### Scenario#130.02: A forge that stops answering is reported once
|
|
|
|
So that the log names the outage without repeating it every minute while the forge stays silent.
|
|
|
|
- **Given** the forge answered for a repository
|
|
- **When** the forge stops answering and is asked three times in a row
|
|
- **Then** the warning "Cannot tell whether … is private" is logged once
|
|
|
|
##### Verified by
|
|
|
|
- [RepositoryPrivacyUnitTest: a forge that stops answering is reported once](../../src/test/kotlin/de/hoennig/werkator/server/RepositoryPrivacyUnitTest.kt)
|
|
|
|
## The Solution
|
|
|
|
- `Answer.standsAt(now)` says whether a cached answer is still valid.
|
|
- `isPrivate` returns the cached answer or calls `ask`.
|
|
- `ask` reads the visibility, warns when a known answer turns unknown, and stores the new answer.
|
|
|
|
Measured locally with PIT on `RepositoryPrivacy`:
|
|
|
|
| Method | Mutation-CRAP before | after |
|
|
|-------------------------------|---------------------:|------:|
|
|
| `RepositoryPrivacy.isPrivate` | 16.40 | 6.04 |
|
|
| `RepositoryPrivacy.ask` | new | 6.11 |
|
|
| `Answer.standsAt` | new | 3.00 |
|
|
|
|
The gate stays at 15.
|
|
|
|
## Prerequisite PRs
|
|
|
|
- PR#129 — this branch is stacked on it, for the version and the release notes.
|
|
|
|
## Follow-up PRs
|
|
|
|
- PR#131 splits two more methods of `ConfigLoader` into smaller steps, so that their scores drop below 15.
|
|
`ConfigLoader.renameLegacySandbox` is at 15.93.
|
|
`ConfigLoader.checkRestartsInstance` is at exactly 15.00: one more surviving mutant would put it above the gate.
|