Public Access
Merge branch 'claude/main-page-group-hierarchy-3a3210'
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Security.Cryptography;
|
||||
using DodoSSH.Client.Domain;
|
||||
using DodoSSH.Client.Storage;
|
||||
using DodoSSH.Client.Sync;
|
||||
using DodoSSH.Contracts;
|
||||
using DodoSSH.Crypto;
|
||||
@@ -151,6 +152,63 @@ public sealed class AadResourceTypeTests
|
||||
.ShouldBe(ItemKinds.SyncedTypes, ignoreOrder: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The same pairing, made a second time in the storage layer, and every type must be in it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <c>AadResourceTypes.For</c> is the cache's copy of the table above: the ciphers seal an item for the
|
||||
/// <em>server</em>, and this seals the two things the local cache holds in the clear — a relay host's
|
||||
/// address, and the values a merge overrode. A type missing from it throws rather than mis-seals, which
|
||||
/// sounds like the safe failure and is not: <c>ConflictStore.RecordAsync</c> calls it unconditionally, so
|
||||
/// the exception lands on the path that records what a merge discarded.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is written after finding three types missing from it — <c>ConnectionLogEntry</c>,
|
||||
/// <c>ActivityLogEntry</c> and <c>ObjectStore</c> went two shipping phases without an arm, because the
|
||||
/// only unconditional caller is one a test suite reaches solely by causing a real merge conflict. Asserted
|
||||
/// over the whole wire enum rather than over <c>ItemKinds.SyncedTypes</c>, which is the stronger claim and
|
||||
/// the one the switch actually makes: the two reserved association types have arms too.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public void EverySyncableType_HasAnArmInTheStorageMapping()
|
||||
{
|
||||
var missing = new List<SyncEntityType>();
|
||||
|
||||
foreach (var wire in Enum.GetValues<SyncEntityType>())
|
||||
{
|
||||
if (wire == SyncEntityType.Unspecified)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CryptoSpec.AadResourceType resource;
|
||||
|
||||
try
|
||||
{
|
||||
resource = AadResourceTypes.For(wire);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
missing.Add(wire);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Same name, as the cipher table demands — a wrong-but-present arm is the failure this half
|
||||
// would otherwise wave through.
|
||||
Enum.GetName(resource).ShouldBe(
|
||||
Enum.GetName(wire),
|
||||
$"AadResourceTypes.For({wire}) returns {resource}, which binds this type's cache records "
|
||||
+ "to another type's resource.");
|
||||
}
|
||||
|
||||
missing.ShouldBeEmpty(
|
||||
"every syncable type needs an arm in AadResourceTypes.For, or a conflict recorded against one "
|
||||
+ "of these throws instead of being written — and the conflict log is what justifies the merge "
|
||||
+ "picking a winner.");
|
||||
}
|
||||
|
||||
private static EncryptedPayload SealSample(
|
||||
SyncEntityType wire,
|
||||
byte[] vaultKey,
|
||||
|
||||
Reference in New Issue
Block a user