Specs: how to run the eight compat tests on a copy of INBUXA's data, and the statuses of tests 10, 11, 17 to 19

docs/spec/compat-tests.md lists each compat test, what it needs, what it
checks and what a failure means, and says plainly that they run against a
copy only, since the monitoring one purges the history it reads. The
scale-out and per-domain statuses record the acceptance tests that now
run.
This commit is contained in:
2026-09-19 15:11:04 -07:00
parent c0377df942
commit cee4fd6bc6
3 changed files with 96 additions and 18 deletions
+70
View File
@@ -0,0 +1,70 @@
# Running the compat tests against a copy of INBUXA's data
Status: 2026-09-19.
Each feature spec has one **(compat)** acceptance test: the check that
INBUXA's own data opens in inbuxa-server and reads back as it did on the
Enterprise server (SPEC.md §7). They are written, `#[ignore]`d, and unrun,
because the repository has no copy of that data.
**Run them against a copy, never against the live server.** Two of them
delete data as part of what they check: `monitoring_compat` purges the
telemetry history it has just read, and `per_domain_directory_compat` reads
only, but the monitoring one is enough reason to treat the whole set as
destructive. The brief bars touching INBUXA's production server, and these
tests are not an exception.
## What you need
1. A copy of the data store, opened with the same `STORE` backend the copy
was taken from, and a `TMPDIR` pointing at it. `NO_INSERT=1` stops the
harness from resetting or seeding it.
2. `INBUXA_COMPAT_ADMIN`, as `name:password`, for a server-level
administrator in that copy.
3. For `tenant_compat` only: `INBUXA_COMPAT_EXPECTED`, a JSON file recorded
from the Enterprise server before the move:
```json
{
"tenants": {"<id>": {"name": "...", "quotas": {}, "members": ["<id>"]}},
"tenantAdmins": {"<name>": {"password": "...", "accounts": ["<id>"],
"domains": ["<id>"]}}
}
```
## Running one
```
NO_INSERT=1 STORE=<backend> TMPDIR=/path/to/copy \
INBUXA_COMPAT_ADMIN='[email protected]:<password>' \
RUST_MIN_STACK=8388608 \
cargo test -p tests --features <backends> <test name> -- --ignored --exact
```
`<test name>` is the full path, such as `system::tenant::tenant_compat`.
Run them one at a time: each starts a server on fixed ports.
## The eight tests
| Test | Feature | What it checks |
|---|---|---|
| `system::tenant::tenant_compat` | 1, multi-tenancy | Tenants, their members and quotas read back unchanged, and each tenant administrator sees what it saw before (needs `INBUXA_COMPAT_EXPECTED`) |
| `system::masked_email::masked_email_compat` | 2, masked email | Existing masked addresses still deliver, and their state reads back |
| `system::undelete::undelete_compat` | 3, undelete | Archived items are still listed and restorable |
| `system::branding::branding_compat` | 4, branding | Every domain's and tenant's logo, `logoUrl` and the three templates read back as stored |
| `system::ai::ai_compat` | 5, AI spam | The twelve `LLM_*` tags and their scores |
| `system::monitoring::monitoring_compat` | 6, monitoring | Retention, stores and `indexTelemetry` as observed; old history in the stripped encoding is skipped, not an error, and is gone after one purge (**deletes history**) |
| `scim::scim_compat` | 7, SCIM | No domain open to SCIM, and no account with an `externalId`, as observed |
| `directory::per_domain::per_domain_directory_compat` | 9, per-domain directories | No directory, no server default, and no domain with its own directory: any domain with one is a cutover blocker |
## What a failure means
- `tenant_compat`, `masked_email_compat`, `undelete_compat`,
`branding_compat`, `ai_compat`: the fork reads that data differently from
the Enterprise server. Treat as a cutover blocker and fix before moving.
- `monitoring_compat`: old telemetry that can't be decoded is expected and
is skipped; a failure here means the settings differ from what was
observed.
- `scim_compat` and `per_domain_directory_compat`: they assert what was
observed on 2026-09-18, that INBUXA uses neither feature. A failure means
it has started to, and that feature's cutover notes then apply.
+14 -8
View File
@@ -551,18 +551,18 @@ marked `inbuxa:`.
- **Tests.** `directory::per_domain::per_domain_directory_tests` covers - **Tests.** `directory::per_domain::per_domain_directory_tests` covers
tests 1, 3, 4, 6, 7, 9, 11, 15 and 19, and DIR-20 and DIR-21, over SQL tests 1, 3, 4, 6, 7, 9, 11, 15 and 19, and DIR-20 and DIR-21, over SQL
directories on SQLite files, with no container. `directory_tests` runs a directories on SQLite files, with no container. `directory_tests` runs a
new `oidc` module in place of the removed one, against Keycloak: tests 5, new `oidc` module in place of the removed one, against Keycloak, whose
8, 12, 13, 14, 16 and 17 in part (below). SCIM's acceptance test 5 container now imports a second realm: tests 5, 8, 10, 12, 13, 14, 16, 17
and 18, the last two in part (below). SCIM's acceptance test 5
(`scim_oidc_tests`) now runs and passes. (`scim_oidc_tests`) now runs and passes.
- **Test 20 (compat)** is `per_domain_directory_compat`, ignored, and unrun - **Test 20 (compat)** is `per_domain_directory_compat`, ignored, and unrun
until a copy of INBUXA's data is provided. It checks observed 1. until a copy of INBUXA's data is provided. It checks observed 1.
- **Not exercised, or only in part:** - **Not exercised, or only in part:**
- Test 2 and test 9 use an SQL directory that can't open instead of a - Test 2 and test 9 use an SQL directory that can't open instead of a
stopped LDAP server, and test 18 (a stopped provider, and the sign-in stopped LDAP server.
ban) isn't run: the Keycloak container is shared. - Test 12's later sign-ins (an empty groups claim clearing groups, a
- Test 10 needs a second provider, and test 12's later sign-ins (an empty missing one keeping them) need changes to Keycloak users, and aren't
groups claim clearing groups, a missing one keeping them) need changes run.
to Keycloak users; neither is run.
- Test 13 is checked through synchronization itself, since the realm's - Test 13 is checked through synchronization itself, since the realm's
users aren't on the tenant's domain. Test 14 reuses an account an users aren't on the tenant's domain. Test 14 reuses an account an
administrator made, not one from an earlier LDAP directory. administrator made, not one from an earlier LDAP directory.
@@ -570,7 +570,10 @@ marked `inbuxa:`.
token. Keycloak grants every required scope whatever is asked, so the token. Keycloak grants every required scope whatever is asked, so the
missing-scope refusal isn't reached; audience and key rotation aren't missing-scope refusal isn't reached; audience and key rotation aren't
run. Test 17 checks password sign-in and a malformed token; an opaque run. Test 17 checks password sign-in and a malformed token; an opaque
token and `usernameDomain` aren't run. token that the provider accepts, and `usernameDomain`, aren't run.
Test 18 stops the provider and checks an outage doesn't ban the
client, and that bad tokens do; it doesn't measure the failure's
latency.
- DIR-22's rule that `Authentication.directoryId` names a server-level - DIR-22's rule that `Authentication.directoryId` names a server-level
directory, and DIR-24 (a tenant administrator setting its own domains' directory, and DIR-24 (a tenant administrator setting its own domains'
directory), aren't tested. directory), aren't tested.
@@ -583,6 +586,9 @@ marked `inbuxa:`.
reload from applying. reload from applying.
- A server default naming no directory is unavailable, like a domain's - A server default naming no directory is unavailable, like a domain's
(DIR-5); it used to mean the internal directory. (DIR-5); it used to mean the internal directory.
- A token the OIDC directory refuses is an authentication failure, so it
counts toward the sign-in ban (DIR-30); it used to be an error, which
counts toward nothing.
- **Known limits, not requirements of this spec:** - **Known limits, not requirements of this spec:**
- An SQL directory on a SQLite path that can't be opened holds the reload, - An SQL directory on a SQLite path that can't be opened holds the reload,
and the request that caused it, for the pool's 30-second connection and the request that caused it, for the pool's 30-second connection
+12 -10
View File
@@ -553,18 +553,19 @@ Decision).
treats as two members. `store::replica::replica_tests`, built with treats as two members. `store::replica::replica_tests`, built with
`postgres` and run with `STORE=PostgreSqlReplicated`, runs a primary and a `postgres` and run with `STORE=PostgreSqlReplicated`, runs a primary and a
streaming hot standby in containers and covers tests 9, 10, 12, 13, 14 streaming hot standby in containers and covers tests 9, 10, 12, 13, 14
and 15. Test 1 is the existing store, blob and protocol suites passing and 15. `replica_cluster_tests` (with `redis`) covers test 11, and
unchanged. `replica_mysql` covers tests 17 to 19 against two MySQL pairs, one
replicating with GTIDs and one by binary log position. Test 1 is the
existing store, blob and protocol suites passing unchanged.
- **Not exercised:** test 3's downloads over JMAP and IMAP after a restart - **Not exercised:** test 3's downloads over JMAP and IMAP after a restart
(the same blob reads are checked at the store), test 5's queued delivery (the same blob reads are checked at the store), test 5's queued delivery
(the failing write is checked), test 21 (one of two Redis servers stopped), (the failing write is checked), test 21 (one of two Redis servers stopped),
the `resetRateLimiters` and `removeLock*` maintenance types (the store the `resetRateLimiters` and `removeLock*` maintenance types (the store
operations they use are checked), test 11 (two nodes), test 16 (the operations they use are checked), and test 16 (the primary stopped).
primary stopped), and tests 17 to 19: the MySQL code (GTID and Test 9 checks that the replica served the reads, not the replica's
`Seconds_Behind_Source` lag, the read-only and commit-order checks) is statement log, and test 15 checks full-text search, not a SQL directory.
built but hasn't run against a MySQL replica. Test 9 checks that the Test 11 uses one server and a second replicated store with its own
replica served the reads, not the replica's statement log, and test 15 marks, rather than two whole nodes.
checks full-text search, not a SQL directory.
- **Settled from the code, not a change of intent:** - **Settled from the code, not a change of intent:**
- The FileSystem backend reports any unreadable file as missing, so a - The FileSystem backend reports any unreadable file as missing, so a
FileSystem member that can't be read looks like a miss (ST-17's search FileSystem member that can't be read looks like a miss (ST-17's search
@@ -590,8 +591,9 @@ Decision).
- Placement is the fork's own (ST-16), so an install coming from a - Placement is the fork's own (ST-16), so an install coming from a
sharded upstream deployment reads through ST-17's search (open sharded upstream deployment reads through ST-17's search (open
question). question).
- ST-7's step 4 raises the mark from a JMAP `sinceState` only; IMAP - ST-7's step 4 raises the mark from a JMAP `sinceState` and an IMAP
`CONDSTORE` and `QRESYNC` values and push resumption don't yet. `FETCH ... CHANGEDSINCE`; a JMAP `queryChanges` state, `QRESYNC` on
SELECT and push resumption don't yet.
- The store's `enterprise` Cargo feature stays: other crates' feature - The store's `enterprise` Cargo feature stays: other crates' feature
lists name it. lists name it.