Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a89e673
test: add end-to-end smoke script for server startup and shutdown
meketreve Aug 13, 2026
c8d796e
test: check Win32 return values and add top-level trap for exit 7
meketreve Aug 13, 2026
60be7ba
test: add Perpetuum.Tests project with ValueTypeExtensions coverage
meketreve Aug 13, 2026
47c261b
test: declare Windows platform support to fix CA1416 warnings
meketreve Aug 13, 2026
9262d65
test: cover Guard throw-if extension methods
meketreve Aug 13, 2026
bfda47a
test: cover Guard throw-if extension methods
meketreve Aug 13, 2026
45a56f8
test: cover Guard throw-if extension methods
meketreve Aug 13, 2026
b695060
test: add recording logger and static service locator fixture
meketreve Aug 13, 2026
604f511
test: add recording fake for the ADO.NET data layer
meketreve Aug 13, 2026
c84ff05
test: cover DbQuery parameter, timeout and result handling
meketreve Aug 13, 2026
f19f245
test: cover DbQuery command type inference and ExecuteSingleRow
meketreve Aug 13, 2026
b6ac383
test: add integration project with game root discovery and skip behav…
meketreve Aug 14, 2026
43712cb
test: assert every documented stored procedure and function exists
meketreve Aug 14, 2026
720f718
test: compare documented stored procedures by schema-qualified name
meketreve Aug 14, 2026
4006d12
test: execute the insurance price query against the real schema
meketreve Aug 14, 2026
513d786
test: document the insurance anchor's rationale and schema-qualify th…
meketreve Aug 14, 2026
ad44790
test: add ISSUE-039 regression pinning the insurance cache reload out…
meketreve Aug 14, 2026
9ba93f3
test: document the three-red mechanism in the ISSUE-039 regression test
meketreve Aug 14, 2026
acd57f1
test: add ISSUE-033 regression for roaming presences with no flocks
meketreve Aug 14, 2026
38bd68a
test: apply final review fix wave for automated-test-suite branch
meketreve Aug 14, 2026
3ae0bc1
test: correct an inaccurate clause in the RecordingLogger filter comment
meketreve Aug 14, 2026
a59121c
ci: run the unit test tier on pushes and pull requests to develop
meketreve Aug 14, 2026
c193a11
docs: record the test suite in the documentation set and the backlog
meketreve Aug 14, 2026
8c1c40b
docs: correct the Db.Query() call site count in TESTING.md
meketreve Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ jobs:
path: ${{ env.Workspace }}/bin/x64/Release/net8.0
if: ${{ github.event_name == 'push'}}

test:

runs-on: windows-latest

steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Run unit tests
run: dotnet test src/Perpetuum.Tests/Perpetuum.Tests.csproj --no-restore --configuration Release -p:Platform=x64

build-admintool-installer:

runs-on: windows-latest
Expand Down
21 changes: 18 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ CI:
Output:
- `bin/x64/Release/net8.0`

There are currently no automated tests.
Tests:

```bash
dotnet test src/Perpetuum.Tests/Perpetuum.Tests.csproj -c Release -p:Platform=x64
```

This is the unit tier and needs no setup. The integration tier and the smoke script need a configured
`GameRoot` and a live database — see `docs/codebase/TESTING.md`.

---

Expand Down Expand Up @@ -280,14 +287,22 @@ Prefer:

# Testing & Validation

There is currently no automated test suite.
An automated test suite exists in three tiers — unit, integration and smoke. It does not cover the
whole codebase. `docs/codebase/TESTING.md` states what is covered, what is not, and how to run each
tier.

Claude MUST:
- propose manual validation steps
- run the unit tier after changing code it covers
- propose tests first, and manual validation for what tests cannot reach
- propose manual validation steps for gameplay behaviour, which no tier covers
- identify affected gameplay systems
- identify affected DB state
- identify likely regression areas

Claude MUST NOT:
- restructure production code to make a test possible without saying so explicitly
- add a regression test without observing it fail against the unfixed code

---

# Response Expectations
Expand Down
14 changes: 14 additions & 0 deletions PerpetuumServer2.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perpetuum.ServerService2",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Perpetuum.AdminTool", "src\Perpetuum.AdminTool\Perpetuum.AdminTool.csproj", "{A7D1E3C5-9F4B-42E8-8A6C-B5D7F1E9C2A0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Perpetuum.Tests", "src\Perpetuum.Tests\Perpetuum.Tests.csproj", "{C8C45427-6E5C-496C-9446-0817EADC05DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Perpetuum.Tests.Integration", "src\Perpetuum.Tests.Integration\Perpetuum.Tests.Integration.csproj", "{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -65,6 +69,14 @@ Global
{A7D1E3C5-9F4B-42E8-8A6C-B5D7F1E9C2A0}.Debug|x64.Build.0 = Debug|x64
{A7D1E3C5-9F4B-42E8-8A6C-B5D7F1E9C2A0}.Release|x64.ActiveCfg = Release|x64
{A7D1E3C5-9F4B-42E8-8A6C-B5D7F1E9C2A0}.Release|x64.Build.0 = Release|x64
{C8C45427-6E5C-496C-9446-0817EADC05DD}.Debug|x64.ActiveCfg = Debug|x64
{C8C45427-6E5C-496C-9446-0817EADC05DD}.Debug|x64.Build.0 = Debug|x64
{C8C45427-6E5C-496C-9446-0817EADC05DD}.Release|x64.ActiveCfg = Release|x64
{C8C45427-6E5C-496C-9446-0817EADC05DD}.Release|x64.Build.0 = Release|x64
{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B}.Debug|x64.ActiveCfg = Debug|x64
{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B}.Debug|x64.Build.0 = Debug|x64
{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B}.Release|x64.ActiveCfg = Release|x64
{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -79,6 +91,8 @@ Global
{D3F8A2B1-6C9E-4D7F-A5B8-2E0C4F9A3D6B} = {0BC991A1-133C-49ED-A141-80E2A906898B}
{A2FCE930-E013-4731-B354-F7DA00322D38} = {0BC991A1-133C-49ED-A141-80E2A906898B}
{A7D1E3C5-9F4B-42E8-8A6C-B5D7F1E9C2A0} = {0BC991A1-133C-49ED-A141-80E2A906898B}
{C8C45427-6E5C-496C-9446-0817EADC05DD} = {0BC991A1-133C-49ED-A141-80E2A906898B}
{ABE8E004-66D6-4D40-AEBF-3CFBD041E29B} = {0BC991A1-133C-49ED-A141-80E2A906898B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {91874B60-30B0-4B48-9155-370E40BC70E6}
Expand Down
80 changes: 79 additions & 1 deletion docs/backlog/improvements.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,84 @@
# Last ID used

044
045

## IMPROVEMENT-045 - Automated test suite

Status: IN_PROGRESS
Priority: MEDIUM
Area: Testing / Infrastructure

### Description

Introduce an automated test suite covering the whole project, in three tiers: a smoke script that runs
the real server end to end, a unit tier behind fakes for the four static service locators, and an
integration tier that runs against the real database.

Coverage is partial by design and grows in stages. Stages 0-4 are implemented; stages 5-10 are listed
under Proposed Implementation and are not started.

### Impact

Every change to core systems is currently validated by starting a server and watching the log. That
answer does not survive the next change, and it is re-derived by hand every time.

Two defects found in this repository in the last week — [[ISSUE-033]] and [[ISSUE-039]] — are now
regression tests, each observed failing with its fix reverted. Neither would have been caught by
inspection: ISSUE-039 left a running server quoting stale insurance prices with no error in the log at
all.

[[ISSUE-038]] already asks in writing for "an automated test client" looping session
connect/disconnect while sampling `dotnet-gcdump`. That is a soak harness rather than a test suite, but
the demand for automation is already on record.

There is a second reason, and it is the stronger one. The share of AI-authored code in this repository
is rising. The value of an automated suite is that it answers "did this break something" without a
human re-deriving the answer for every contribution, from any author.

### Proposed Implementation

Three tiers, because no single tier catches what this repository actually breaks. ISSUE-039 only
manifests when a real `SqlConnection.Open()` reads `Transaction.Current` and finds a completed scope —
a faked connection passes it.

| Tier | Project | Needs |
|---|---|---|
| 1 — smoke | `tools/smoke-test.ps1` | A configured `GameRoot` and a live database |
| 2 — unit | `src/Perpetuum.Tests` | Nothing; runs in CI |
| 3 — integration | `src/Perpetuum.Tests.Integration` | A configured `GameRoot` and a live database |

Delivered (stages 0-4): infrastructure and fakes, the smoke script, `Guard.cs` and
`ValueTypeExtensions.cs`, the data layer against both the fake and the real schema, and the two
regression tests.

Remaining stages, in order:

| # | Stage | Tier |
|---|---|---|
| 5 | Entity system — `Entity`, `EntityDefault`, `EntityDynamicProperties` in isolation | 2 |
| 6 | Module state machines — transitions in `ActiveModule.States.cs` | 2 |
| 7 | Season service — tier grant, objective completion, leaderboard delivery, intro-mail idempotency, end-of-season processing | 2+3 |
| 8 | Request handlers — fake session/request infrastructure plus one handler per dispatch category | 2 |
| 9 | Mission engine — deterministic resolve against fixed data | 2+3 |
| 10 | Concurrency — only what can be made deterministic: `ProcessManager`, `MessageSender` | 2 |

### Notes

- **No production code changes.** The four existing static service locators (`Logger.Current`,
`Db.DbQueryFactory`, `EntityDefault.Reader`, `Entity.Services`) turned out to be sufficient seams for
everything in stages 0-4. If a later stage genuinely cannot be tested without a new seam, that is
raised in the pull request rather than slipped in — `CLAUDE.md` forbids speculative refactors.
- **No synthetic schema.** Tier 3 runs against the real `perpetuumsa`. Duplicating the DDL would drift
from production, and every developer who touches this code already has the standard environment.
`PERPETUUM_GAMEROOT` is the only machine-specific input and its absence makes tests skip, not fail.
- **Coverage is not the goal.** Covering all 585 files of `Perpetuum.RequestHandlers` is explicitly a
non-goal. Stage 8 is one handler per dispatch category, not 200.
- Stage 10 is scoped to what can be made deterministic. A flaky concurrency test is worse than no test:
it trains the team to ignore red.
- Before stages 7 and 9, where the number of stubs multiplies, two hardening items: make the data fake
fail loudly when no registered pattern matches a command instead of returning an empty result set,
and give the assembly-wide recording logger an automatic reset instead of relying on each test class
to clear it.

## IMPROVEMENT-044 - Disable NPC flee behavior (player complaints)

Expand Down
6 changes: 4 additions & 2 deletions docs/codebase/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,10 @@ consumed by zones to clean up zone sessions.
These are write-once at startup, read-only thereafter.
- **Platform:** `[SupportedOSPlatform("windows")]` on both `Perpetuum.Server` and
`Perpetuum.Bootstrapper` assemblies — Windows-only due to native dependencies.
- **No automated tests:** The project has no test projects. Validation is manual or via
the `Perpetuum.AdminTool` WPF application.
- **Partial test coverage:** `src/Perpetuum.Tests` (unit) and `src/Perpetuum.Tests.Integration`
(against the real database) cover the data layer, validation helpers and two regression paths.
Gameplay behaviour is still validated manually or via the `Perpetuum.AdminTool` WPF application.
See `docs/codebase/TESTING.md`.
- **SQL Server only:** `Microsoft.Data.SqlClient` is hard-wired; no abstraction layer.

## Anti-Patterns
Expand Down
8 changes: 4 additions & 4 deletions docs/codebase/CONCERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@ The `MissionHandler`, `MissionInProgress`, `MissionProcessorDeliverMission`, `Pr

## Missing Infrastructure

### No Automated Tests
### Partial Test Coverage

The repository has zero automated tests (unit, integration, or functional). CLAUDE.md states this explicitly.
A test suite exists (`src/Perpetuum.Tests`, `src/Perpetuum.Tests.Integration`, `tools/smoke-test.ps1`) but covers only the data layer, validation helpers and two regression paths. The subsystems this document calls high-risk are still untested.

**Impact:** Every change to core systems — combat calculations, mission rewards, market transactions, season point accrual must be manually validated in a running server with a connected database. Regressions are invisible until they reach production or are found by players.
**Impact:** Changes to combat calculations, mission rewards, market transactions and season point accrual must still be manually validated in a running server with a connected database. Regressions in those areas remain invisible until they reach production or are found by players.

**Fix approach:** Start with pure-logic unit tests for `FastRandom`, economy formulas, mission reward calculations, and season point math. These have no external dependencies and provide immediate value.
**Fix approach:** Continue along the coverage map in `IMPROVEMENT-045` — entity system, module state machines, season service, request handlers, mission engine, concurrency. See `docs/codebase/TESTING.md` for what is covered today.

---

Expand Down
12 changes: 9 additions & 3 deletions docs/codebase/STACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,15 @@
- Runner: `windows-latest`
- Trigger: push/PR to `develop` branch
- Publishes build artifact `Perpetuum-Server-v2-{sha}` on push
- Only `Perpetuum.ServerService2` project is built in CI

**No automated tests** — no test project, no test framework configured.
- Only `Perpetuum.ServerService2` project is built in the `build` job
- A `test` job runs the unit tier; the integration tier is not referenced in CI

**Testing:**
- Framework: xUnit v3, with NSubstitute for interface doubles
- `src/Perpetuum.Tests` — unit tier, no external dependencies, runs in CI
- `src/Perpetuum.Tests.Integration` — runs against the real database, skipped when `PERPETUUM_GAMEROOT` is unset
- `tools/smoke-test.ps1` — builds, starts the server, asserts on the startup and shutdown log
- Coverage is partial by design; see `docs/codebase/TESTING.md`

**Unsafe code:**
- `<AllowUnsafeBlocks>true</AllowUnsafeBlocks>` in `src/Perpetuum/Perpetuum.csproj`
Expand Down
Loading
Loading