Declare snapshot-bound direct canvas membership counts in model streams
This commit is contained in:
@@ -18,9 +18,22 @@ func writeCanvasModelStream(ctx context.Context, w http.ResponseWriter, model ca
|
||||
return
|
||||
}
|
||||
view := model.view(nil)
|
||||
// A count covers direct members only; an empty canvas is explicit too.
|
||||
counts := map[string]int{}
|
||||
for _, canvas := range view.Canvases {
|
||||
counts[canvas.ID] = 0
|
||||
}
|
||||
for _, element := range view.Elements {
|
||||
owner := modelString(element["ownerCanvasId"])
|
||||
if _, ok := counts[owner]; !ok {
|
||||
reject(w, 500, "invalid_model_coverage")
|
||||
return
|
||||
}
|
||||
counts[owner]++
|
||||
}
|
||||
header := response{"streamVersion": 1, "kind": "header", "sequence": 0, "snapshotToken": token,
|
||||
"documentFormatVersion": canvasModelFormat, "projectId": model.Root, "canvases": view.Canvases,
|
||||
"versions": view.Versions, "tombstones": view.Tombstones, "removedCanvasIds": view.Removed, "elementCount": len(view.Elements)}
|
||||
"versions": view.Versions, "tombstones": view.Tombstones, "removedCanvasIds": view.Removed, "elementCount": len(view.Elements), "canvasElementCounts": counts}
|
||||
const maxLine = 8 * 1024 * 1024
|
||||
const maxBytes = 64 * 1024 * 1024
|
||||
sequence, total := 0, 0
|
||||
|
||||
@@ -90,3 +90,27 @@ func TestCanonicalModelStreamCancellationNeverClaimsCompletion(t *testing.T) {
|
||||
t.Fatal("cancelled stream wrote a tail", len(records))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalModelStreamDeclaresDirectScopeCountsIncludingEmptyCanvases(t *testing.T) {
|
||||
model := modelTestDocument()
|
||||
empty, nested := modelTestID(41), modelTestID(42)
|
||||
model.Canvases[empty] = modelCanvas{ID: empty, Parent: &modelParent{CanvasID: model.Root, EntryElementID: "frame-empty"}}
|
||||
model.Canvases[nested] = modelCanvas{ID: nested, Parent: &modelParent{CanvasID: model.Root, EntryElementID: "frame-nested"}}
|
||||
model.Versions[empty], model.Versions[nested] = 1, 1
|
||||
model.Elements["frame-empty"] = modelTestNode("frame-empty", model.Root)
|
||||
model.Elements["frame-nested"] = modelTestNode("frame-nested", model.Root)
|
||||
model.Elements["nested-node"] = modelTestNode("nested-node", nested)
|
||||
writer := httptest.NewRecorder()
|
||||
writeCanvasModelStream(context.Background(), writer, model)
|
||||
records := streamRecords(t, writer)
|
||||
if !modelEqual(records[0]["canvasElementCounts"], map[string]int{model.Root: 3, empty: 0, nested: 1}) {
|
||||
t.Fatal("scope counts must count direct members, preserve empty scopes and match the captured snapshot")
|
||||
}
|
||||
bad := modelTestDocument()
|
||||
bad.Elements["a"]["ownerCanvasId"] = "foreign"
|
||||
failed := httptest.NewRecorder()
|
||||
writeCanvasModelStream(context.Background(), failed, bad)
|
||||
if failed.Code != 500 || failed.Flushed {
|
||||
t.Fatal("invalid owner must fail before publishing a scope certificate")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user