fix(gateway): resolve 2026-06-18 array-write review findings
- Server-057: extend []-suffix normalization to AddItemBulk/AddBufferedItem so bulk-added array tags bind write-capable handles (authz check, worker bind, and registration kept consistent); update gateway.md + client READMEs. Tests: AddItemBulk/AddBufferedItem wiring. - Server-058: assert []-fallback-resolved bare array names are still denied when out of read/write scope and that MaxWriteClassification is enforced on suffixed array registrations. - Contracts-023/024/025: round-trip + field-19 descriptor pin for MxSparseArray; document MxSparseArray in docs/Contracts.md; enumerate it in the protocol-version-3 test summary. - Tests-040: add wiring tests for the six uncovered sparse-write arms (WriteSecured, Write2, WriteSecured2, Write2Bulk, WriteSecuredBulk, WriteSecured2Bulk). dotnet build + targeted tests green (184 passed).
This commit is contained in:
@@ -1588,4 +1588,87 @@ public sealed class ProtobufContractRoundTripTests
|
||||
Assert.Equal(150UL, parsed.ReplayGap.RequestedAfterSequence);
|
||||
Assert.Equal(200UL, parsed.ReplayGap.OldestAvailableSequence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pins the wire field number for <c>MxValue.sparse_array_value</c> (19)
|
||||
/// via the generated constant, pins the <see cref="MxSparseArray"/> and
|
||||
/// <see cref="MxSparseElement"/> field numbers by name + number against the
|
||||
/// descriptor, and round-trips an <see cref="MxValue"/> carrying a
|
||||
/// <see cref="MxSparseArray"/> with at least one <see cref="MxSparseElement"/>
|
||||
/// so a future renumber or type-narrowing is caught at the contract level.
|
||||
/// Also verifies that an all-defaults <see cref="MxSparseArray"/> (no elements)
|
||||
/// is not a proto-level error. See Contracts-023.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void MxValue_RoundTripsSparseArrayValueAndPinsFieldNumbers()
|
||||
{
|
||||
// Pin MxValue.sparse_array_value wire field number == 19.
|
||||
Assert.Equal(19, MxValue.SparseArrayValueFieldNumber);
|
||||
|
||||
// Pin MxSparseArray field numbers by name + number.
|
||||
var sparseArrayFields = MxSparseArray.Descriptor.Fields;
|
||||
Assert.Equal(1, sparseArrayFields[MxSparseArray.ElementDataTypeFieldNumber].FieldNumber);
|
||||
Assert.Equal("element_data_type", sparseArrayFields[MxSparseArray.ElementDataTypeFieldNumber].Name);
|
||||
Assert.Equal(2, sparseArrayFields[MxSparseArray.TotalLengthFieldNumber].FieldNumber);
|
||||
Assert.Equal("total_length", sparseArrayFields[MxSparseArray.TotalLengthFieldNumber].Name);
|
||||
Assert.Equal(3, sparseArrayFields[MxSparseArray.ElementsFieldNumber].FieldNumber);
|
||||
Assert.Equal("elements", sparseArrayFields[MxSparseArray.ElementsFieldNumber].Name);
|
||||
|
||||
// Pin MxSparseElement field numbers by name + number.
|
||||
var sparseElementFields = MxSparseElement.Descriptor.Fields;
|
||||
Assert.Equal(1, sparseElementFields[MxSparseElement.IndexFieldNumber].FieldNumber);
|
||||
Assert.Equal("index", sparseElementFields[MxSparseElement.IndexFieldNumber].Name);
|
||||
Assert.Equal(2, sparseElementFields[MxSparseElement.ValueFieldNumber].FieldNumber);
|
||||
Assert.Equal("value", sparseElementFields[MxSparseElement.ValueFieldNumber].Name);
|
||||
|
||||
// Round-trip an MxValue with a populated MxSparseArray (one scalar element).
|
||||
var original = new MxValue
|
||||
{
|
||||
DataType = MxDataType.Float,
|
||||
SparseArrayValue = new MxSparseArray
|
||||
{
|
||||
ElementDataType = MxDataType.Float,
|
||||
TotalLength = 4,
|
||||
Elements =
|
||||
{
|
||||
new MxSparseElement
|
||||
{
|
||||
Index = 2,
|
||||
Value = new MxValue
|
||||
{
|
||||
DataType = MxDataType.Float,
|
||||
FloatValue = 3.14f,
|
||||
VariantType = "VT_R4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
var parsed = MxValue.Parser.ParseFrom(original.ToByteArray());
|
||||
|
||||
Assert.Equal(original, parsed);
|
||||
Assert.Equal(MxValue.KindOneofCase.SparseArrayValue, parsed.KindCase);
|
||||
Assert.NotNull(parsed.SparseArrayValue);
|
||||
Assert.Equal(MxDataType.Float, parsed.SparseArrayValue.ElementDataType);
|
||||
Assert.Equal(4u, parsed.SparseArrayValue.TotalLength);
|
||||
var element = Assert.Single(parsed.SparseArrayValue.Elements);
|
||||
Assert.Equal(2u, element.Index);
|
||||
Assert.Equal(3.14f, element.Value.FloatValue);
|
||||
|
||||
// An all-defaults MxSparseArray (no elements) is not a proto-level error.
|
||||
var empty = new MxValue
|
||||
{
|
||||
DataType = MxDataType.Float,
|
||||
SparseArrayValue = new MxSparseArray
|
||||
{
|
||||
ElementDataType = MxDataType.Float,
|
||||
TotalLength = 10,
|
||||
},
|
||||
};
|
||||
var parsedEmpty = MxValue.Parser.ParseFrom(empty.ToByteArray());
|
||||
Assert.Equal(empty, parsedEmpty);
|
||||
Assert.Equal(MxValue.KindOneofCase.SparseArrayValue, parsedEmpty.KindCase);
|
||||
Assert.Empty(parsedEmpty.SparseArrayValue.Elements);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user