@fluid-internal/presence-runtime 2.102.0 → 2.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/packageVersion.d.ts +1 -1
  2. package/dist/packageVersion.js +1 -1
  3. package/dist/packageVersion.js.map +1 -1
  4. package/dist/runtime/extension/containerPresence.d.ts +1 -1
  5. package/dist/runtime/presenceDatastoreManager.d.ts +2 -2
  6. package/dist/runtime/presenceDatastoreManager.d.ts.map +1 -1
  7. package/dist/runtime/presenceDatastoreManager.js.map +1 -1
  8. package/dist/runtime/presenceManager.js.map +1 -1
  9. package/lib/packageVersion.d.ts +1 -1
  10. package/lib/packageVersion.js +1 -1
  11. package/lib/packageVersion.js.map +1 -1
  12. package/lib/runtime/extension/containerPresence.d.ts +1 -1
  13. package/lib/runtime/presenceDatastoreManager.d.ts +2 -2
  14. package/lib/runtime/presenceDatastoreManager.d.ts.map +1 -1
  15. package/lib/runtime/presenceDatastoreManager.js.map +1 -1
  16. package/lib/runtime/presenceManager.js.map +1 -1
  17. package/package.json +15 -15
  18. package/dist/runtime/test/presenceDatastoreManager.spec.js +0 -618
  19. package/dist/runtime/test/presenceDatastoreManager.spec.js.map +0 -1
  20. package/dist/runtime/test/presenceManager.spec.js +0 -651
  21. package/dist/runtime/test/presenceManager.spec.js.map +0 -1
  22. package/dist/states/test/batching.spec.js +0 -843
  23. package/dist/states/test/batching.spec.js.map +0 -1
  24. package/dist/states/test/broadcastControlsTests.js +0 -60
  25. package/dist/states/test/broadcastControlsTests.js.map +0 -1
  26. package/dist/states/test/eventing.spec.js +0 -576
  27. package/dist/states/test/eventing.spec.js.map +0 -1
  28. package/dist/states/test/latestMapValueManager.spec.js +0 -210
  29. package/dist/states/test/latestMapValueManager.spec.js.map +0 -1
  30. package/dist/states/test/latestValueManager.spec.js +0 -193
  31. package/dist/states/test/latestValueManager.spec.js.map +0 -1
  32. package/dist/states/test/mockEphemeralRuntime.js +0 -11
  33. package/dist/states/test/mockEphemeralRuntime.js.map +0 -1
  34. package/dist/states/test/notificationsManager.spec.js +0 -460
  35. package/dist/states/test/notificationsManager.spec.js.map +0 -1
  36. package/dist/states/test/presenceStates.spec.js +0 -73
  37. package/dist/states/test/presenceStates.spec.js.map +0 -1
  38. package/dist/states/test/schemaValidation/protocol.spec.js +0 -246
  39. package/dist/states/test/schemaValidation/protocol.spec.js.map +0 -1
  40. package/dist/states/test/schemaValidation/valueManagers.spec.js +0 -784
  41. package/dist/states/test/schemaValidation/valueManagers.spec.js.map +0 -1
  42. package/dist/states/test/testUtils.js +0 -21
  43. package/dist/states/test/testUtils.js.map +0 -1
  44. package/dist/test/mockEphemeralRuntime.js +0 -175
  45. package/dist/test/mockEphemeralRuntime.js.map +0 -1
  46. package/dist/test/testUtils.js +0 -262
  47. package/dist/test/testUtils.js.map +0 -1
  48. package/dist/test/utils/index.js +0 -27
  49. package/dist/test/utils/index.js.map +0 -1
  50. package/dist/utils/test/timerManager.spec.js +0 -93
  51. package/dist/utils/test/timerManager.spec.js.map +0 -1
  52. package/lib/runtime/test/presenceDatastoreManager.spec.js +0 -616
  53. package/lib/runtime/test/presenceDatastoreManager.spec.js.map +0 -1
  54. package/lib/runtime/test/presenceManager.spec.js +0 -649
  55. package/lib/runtime/test/presenceManager.spec.js.map +0 -1
  56. package/lib/states/test/batching.spec.js +0 -841
  57. package/lib/states/test/batching.spec.js.map +0 -1
  58. package/lib/states/test/broadcastControlsTests.js +0 -56
  59. package/lib/states/test/broadcastControlsTests.js.map +0 -1
  60. package/lib/states/test/eventing.spec.js +0 -574
  61. package/lib/states/test/eventing.spec.js.map +0 -1
  62. package/lib/states/test/latestMapValueManager.spec.js +0 -206
  63. package/lib/states/test/latestMapValueManager.spec.js.map +0 -1
  64. package/lib/states/test/latestValueManager.spec.js +0 -189
  65. package/lib/states/test/latestValueManager.spec.js.map +0 -1
  66. package/lib/states/test/mockEphemeralRuntime.js +0 -6
  67. package/lib/states/test/mockEphemeralRuntime.js.map +0 -1
  68. package/lib/states/test/notificationsManager.spec.js +0 -456
  69. package/lib/states/test/notificationsManager.spec.js.map +0 -1
  70. package/lib/states/test/presenceStates.spec.js +0 -69
  71. package/lib/states/test/presenceStates.spec.js.map +0 -1
  72. package/lib/states/test/schemaValidation/protocol.spec.js +0 -244
  73. package/lib/states/test/schemaValidation/protocol.spec.js.map +0 -1
  74. package/lib/states/test/schemaValidation/valueManagers.spec.js +0 -782
  75. package/lib/states/test/schemaValidation/valueManagers.spec.js.map +0 -1
  76. package/lib/states/test/testUtils.js +0 -6
  77. package/lib/states/test/testUtils.js.map +0 -1
  78. package/lib/test/mockEphemeralRuntime.js +0 -171
  79. package/lib/test/mockEphemeralRuntime.js.map +0 -1
  80. package/lib/test/testUtils.js +0 -251
  81. package/lib/test/testUtils.js.map +0 -1
  82. package/lib/test/utils/index.js +0 -8
  83. package/lib/test/utils/index.js.map +0 -1
  84. package/lib/utils/test/timerManager.spec.js +0 -91
  85. package/lib/utils/test/timerManager.spec.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"valueManagers.spec.js","sourceRoot":"","sources":["../../../../src/states/test/schemaValidation/valueManagers.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type {\n\tAttendee,\n\tLatest,\n\tLatestMap,\n\tPresence,\n} from \"@fluid-internal/presence-definitions\";\nimport type { OpaqueJsonDeserialized } from \"@fluidframework/core-interfaces/internal/exposedUtilityTypes\";\nimport { EventAndErrorTrackingLogger } from \"@fluidframework/test-utils/internal\";\nimport { describe, it, after, afterEach, before, beforeEach } from \"mocha\";\nimport type { SinonFakeTimers } from \"sinon\";\nimport { useFakeTimers } from \"sinon\";\n\nimport { StateFactory } from \"@fluid-internal/presence-runtime/states\";\nimport { toOpaqueJson } from \"@fluid-internal/presence-runtime/utils\";\n\nimport { MockEphemeralRuntime } from \"../mockEphemeralRuntime.js\";\nimport type { InboundPresenceSignalMessage, ProcessSignalFunction } from \"../testUtils.js\";\nimport {\n\tassertFinalExpectations,\n\tattendeeId1,\n\tlocalAttendeeId,\n\tconnectionId1,\n\tinitialLocalClientConnectionId,\n\tcreateSpiedValidator,\n\tprepareConnectedPresence,\n} from \"../testUtils.js\";\n\n/**\n * Workspace updates\n */\ninterface Point3D {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\nconst attendeeUpdate = {\n\t\"clientToSessionId\": {\n\t\t[connectionId1]: {\n\t\t\t\"rev\": 0,\n\t\t\t\"timestamp\": 0,\n\t\t\t\"value\": attendeeId1,\n\t\t},\n\t},\n} as const;\nconst latestUpdate = {\n\t\"latest\": {\n\t\t[attendeeId1]: {\n\t\t\t\"rev\": 1,\n\t\t\t\"timestamp\": 0,\n\t\t\t\"value\": toOpaqueJson({ x: 1, y: 1, z: 1 }),\n\t\t},\n\t},\n} as const;\nconst latestMapUpdate = {\n\t\"latestMap\": {\n\t\t[attendeeId1]: {\n\t\t\t\"rev\": 1,\n\t\t\t\"items\": {\n\t\t\t\t\"key1\": {\n\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"value\": toOpaqueJson({ x: 1, y: 1, z: 1 }),\n\t\t\t\t},\n\t\t\t\t\"key2\": {\n\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"value\": toOpaqueJson({ x: 2, y: 2, z: 2 }),\n\t\t\t\t},\n\t\t\t\t\"invalidKey\": {\n\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"value\": toOpaqueJson({ x: -1, y: -1, z: -1 }),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nfunction datastoreUpdateSignal(\n\tsendTimestamp: number,\n\tvalueObjectName: string,\n\tmetadata:\n\t\t| {\n\t\t\t\t\"rev\": number;\n\t\t\t\t\"timestamp\": number;\n\t\t\t\t\"value\": OpaqueJsonDeserialized<unknown>;\n\t\t }\n\t\t| {\n\t\t\t\t\"rev\": number;\n\t\t\t\t\"items\": Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{\n\t\t\t\t\t\t\"rev\": number;\n\t\t\t\t\t\t\"timestamp\": number;\n\t\t\t\t\t\t\"value\": OpaqueJsonDeserialized<unknown>;\n\t\t\t\t\t}\n\t\t\t\t>;\n\t\t },\n): InboundPresenceSignalMessage {\n\treturn {\n\t\ttype: \"Pres:DatastoreUpdate\",\n\t\tcontent: {\n\t\t\tsendTimestamp,\n\t\t\tavgLatency: 20,\n\t\t\tdata: {\n\t\t\t\t\"system:presence\": attendeeUpdate,\n\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t[valueObjectName]: {\n\t\t\t\t\t\t[attendeeId1]: metadata,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tclientId: connectionId1,\n\t};\n}\n\ninterface ValidatorTestParams {\n\tgetRemoteValue: () => Point3D | undefined;\n\tvalidatorFunction: ReturnType<typeof createSpiedValidator<Point3D>>;\n\texpectedCallCount: number;\n\texpectedValue: Point3D | undefined;\n}\n\n/**\n * Runs a test against a validator by getting the value and matching the resulting data and validator call counts\n * against expectations.\n */\nfunction runValidatorTest(params: ValidatorTestParams): void {\n\tconst initialValue = params.getRemoteValue();\n\tassert.equal(params.validatorFunction.callCount, params.expectedCallCount);\n\tassert.deepEqual(initialValue, params.expectedValue);\n}\n\ninterface MultipleCallsTestParams {\n\tgetRemoteValue: () => Point3D | undefined;\n\texpectedValue: Point3D | undefined;\n\tvalidatorFunction: ReturnType<typeof createSpiedValidator<Point3D>>;\n}\n\n/**\n * Runs a test against a validator by getting the value multiple times and verifying that the validator is not called\n * multiple times.\n */\nfunction runMultipleCallsTest(params: MultipleCallsTestParams): void {\n\t// First call should invoke validator\n\tconst firstValue = params.getRemoteValue();\n\tassert.equal(params.validatorFunction.callCount, 1);\n\tassert.deepEqual(firstValue, params.expectedValue);\n\n\t// Subsequent calls should not invoke validator when data is unchanged\n\tconst secondValue = params.getRemoteValue();\n\tassert.equal(params.validatorFunction.callCount, 1);\n\tconst thirdValue = params.getRemoteValue();\n\tassert.equal(params.validatorFunction.callCount, 1);\n\tassert.deepEqual(secondValue, params.expectedValue);\n\tassert.deepEqual(thirdValue, params.expectedValue);\n}\n\ndescribe(\"Presence/States\", () => {\n\tdescribe(\"Runtime schema validation\", () => {\n\t\tconst afterCleanUp: (() => void)[] = [];\n\t\tconst initialTime = 1000;\n\n\t\ttype UpdateContent = typeof latestUpdate & typeof latestMapUpdate;\n\n\t\tfunction processUpdates(valueManagerUpdates: Record<string, UpdateContent>): void {\n\t\t\tconst updates = { \"system:presence\": attendeeUpdate, ...valueManagerUpdates };\n\n\t\t\tprocessSignal(\n\t\t\t\t[],\n\t\t\t\t{\n\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\tsendTimestamp: clock.now - 10,\n\t\t\t\t\t\tavgLatency: 20,\n\t\t\t\t\t\tdata: updates,\n\t\t\t\t\t},\n\t\t\t\t\tclientId: \"client1\",\n\t\t\t\t},\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\tlet clock: SinonFakeTimers;\n\t\tlet logger: EventAndErrorTrackingLogger;\n\t\tlet presence: Presence;\n\t\tlet processSignal: ProcessSignalFunction;\n\t\tlet runtime: MockEphemeralRuntime;\n\t\tlet remoteAttendee: Attendee;\n\t\tlet validatorCallExpected: boolean | \"once\";\n\t\tlet point3DValidatorFunction: ReturnType<typeof createSpiedValidator<Point3D>>;\n\n\t\tbefore(async () => {\n\t\t\tclock = useFakeTimers();\n\t\t});\n\n\t\t/**\n\t\t * This beforeEach sets up the runtime and presence objects. The `presence` object is owned by attendee2, while\n\t\t * attendee1 acts as a remote attendee for the purposes of the tests.\n\t\t */\n\t\tbeforeEach(() => {\n\t\t\tlogger = new EventAndErrorTrackingLogger();\n\t\t\truntime = new MockEphemeralRuntime(logger);\n\t\t\tclock.setSystemTime(initialTime);\n\t\t\tvalidatorCallExpected = true;\n\t\t\tpoint3DValidatorFunction = createSpiedValidator<Point3D>((d: unknown) => {\n\t\t\t\tif (validatorCallExpected === \"once\") {\n\t\t\t\t\tvalidatorCallExpected = false;\n\t\t\t\t} else {\n\t\t\t\t\tassert(\n\t\t\t\t\t\tvalidatorCallExpected,\n\t\t\t\t\t\t\"point3DValidatorFunction should not be called at this time\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn typeof d === \"object\" ? (d as Point3D) : undefined;\n\t\t\t});\n\n\t\t\t// Create Presence joining session as attendeeId-2. Tests will act as attendee2\n\t\t\t({ presence, processSignal } = prepareConnectedPresence(\n\t\t\t\truntime,\n\t\t\t\tlocalAttendeeId,\n\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\tclock,\n\t\t\t\tlogger,\n\t\t\t));\n\n\t\t\t// Pass a little time (to mimic reality)\n\t\t\tclock.tick(10);\n\n\t\t\t// Process remote client update signal (attendeeId-1 is then part of local client's known session).\n\t\t\tprocessUpdates({\n\t\t\t\t\"s:name:testWorkspace\": { ...latestUpdate, ...latestMapUpdate },\n\t\t\t});\n\n\t\t\t// Pass a little time (to mimic reality)\n\t\t\tclock.tick(10);\n\n\t\t\t// Get attendee references\n\t\t\tremoteAttendee = presence.attendees.getAttendee(attendeeId1);\n\t\t});\n\n\t\tafterEach(function (done: Mocha.Done) {\n\t\t\tclock.reset();\n\t\t\tpoint3DValidatorFunction.resetHistory();\n\n\t\t\t// If the test passed so far, check final expectations.\n\t\t\tif (this.currentTest?.state === \"passed\") {\n\t\t\t\tassertFinalExpectations(runtime, logger);\n\t\t\t}\n\n\t\t\tfor (const cleanUp of afterCleanUp) {\n\t\t\t\tcleanUp();\n\t\t\t}\n\t\t\tafterCleanUp.length = 0;\n\t\t\tdone();\n\t\t});\n\n\t\tafter(() => {\n\t\t\tclock.restore();\n\t\t});\n\n\t\tdescribe(\"Latest validator\", () => {\n\t\t\tlet latest: Latest<Point3D>;\n\n\t\t\t/**\n\t\t\t * This beforeEach sets up the presence workspace itself and gets a reference to it. It then sets some new data as\n\t\t\t * attendee1 by processing a datastore update signal.\n\t\t\t */\n\t\t\tbeforeEach(() => {\n\t\t\t\t// Setup workspace initialization signal\n\t\t\t\truntime.signalsExpected.push([\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\tsendTimestamp: clock.now,\n\t\t\t\t\t\t\tavgLatency: 10,\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t\t[initialLocalClientConnectionId]: {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": localAttendeeId,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\t\"latest\": {\n\t\t\t\t\t\t\t\t\t\t[localAttendeeId]: {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": clock.now,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 0, y: 0, z: 0 }),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t]);\n\n\t\t\t\tconst stateWorkspace = presence.states.getWorkspace(\"name:testWorkspace\", {\n\t\t\t\t\tlatest: StateFactory.latest({\n\t\t\t\t\t\tlocal: { x: 0, y: 0, z: 0 } satisfies Point3D,\n\t\t\t\t\t\tvalidator: point3DValidatorFunction,\n\t\t\t\t\t\tsettings: { allowableUpdateLatencyMs: 0 },\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tlatest = stateWorkspace.states.latest;\n\n\t\t\t\t// Process a valid update signal with Point3D data\n\t\t\t\tprocessSignal(\n\t\t\t\t\t[],\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\tsendTimestamp: clock.now - 10,\n\t\t\t\t\t\t\tavgLatency: 20,\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\"system:presence\": attendeeUpdate,\n\t\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\t\"latest\": {\n\t\t\t\t\t\t\t\t\t\t[attendeeId1]: {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 2,\n\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": clock.now - 10,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 10, y: 20, z: 30 }),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tclientId: \"client1\",\n\t\t\t\t\t},\n\t\t\t\t\tfalse,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tdescribe(\"is not called\", () => {\n\t\t\t\tit(\"by .getRemote()\", () => {\n\t\t\t\t\t// Calling getRemote should not invoke the validator (only a value read will).\n\t\t\t\t\tlatest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t\t});\n\n\t\t\t\tit(\"by .getRemotes()\", () => {\n\t\t\t\t\tfor (const _ of latest.getRemotes()) {\n\t\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tit(\"when accessing .local\", () => {\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0, \"initial call count is wrong\");\n\t\t\t\t\tassert.deepEqual(latest.local, { x: 0, y: 0, z: 0 });\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t\"validator was called on local data\",\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tit(\"when remote data is updated\", () => {\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\n\t\t\t\t\t// Should call validator\n\t\t\t\t\trunValidatorTest({\n\t\t\t\t\t\tgetRemoteValue: () => remoteData.value(),\n\t\t\t\t\t\texpectedCallCount: 1,\n\t\t\t\t\t\texpectedValue: { x: 10, y: 20, z: 30 },\n\t\t\t\t\t\tvalidatorFunction: point3DValidatorFunction,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Send updated data from remote client\n\t\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 50, y: 60, z: 70 }),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Validator is not called by remote update\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tdescribe(\"is called\", () => {\n\t\t\t\tit(\"on first .value() call\", () => {\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\trunValidatorTest({\n\t\t\t\t\t\tgetRemoteValue: () => remoteData.value(),\n\t\t\t\t\t\texpectedCallCount: 1,\n\t\t\t\t\t\texpectedValue: { x: 10, y: 20, z: 30 },\n\t\t\t\t\t\tvalidatorFunction: point3DValidatorFunction,\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tit(\"only once for multiple .value() calls in series and .value() always returns same value\", () => {\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\trunMultipleCallsTest({\n\t\t\t\t\t\tgetRemoteValue: () => remoteData.value(),\n\t\t\t\t\t\texpectedValue: { x: 10, y: 20, z: 30 },\n\t\t\t\t\t\tvalidatorFunction: point3DValidatorFunction,\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tit(\"on .value() call after remote data has changed\", () => {\n\t\t\t\t\t// Get the remote data and read it, verify that the validator is called once.\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.deepEqual(remoteData.value(), { x: 10, y: 20, z: 30 });\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1, \"first call count is wrong\");\n\n\t\t\t\t\t// Send updated data from remote client\n\t\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 50, y: 60, z: 70 }),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Reading the remote value should cause the validator to be called a second time since the data has been changed.\n\t\t\t\t\tconst data2 = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\tdata2.value(),\n\t\t\t\t\t\t{ x: 50, y: 60, z: 70 },\n\t\t\t\t\t\t\"updated remote value is wrong\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t2,\n\t\t\t\t\t\t\"validator should be called twice\",\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tit(\"on .value() call when remote data changes from valid to invalid\", () => {\n\t\t\t\t\t// Get the remote data and read it, verify that the validator is called once.\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.deepEqual(remoteData.value(), { x: 10, y: 20, z: 30 });\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1, \"first call count is wrong\");\n\n\t\t\t\t\t// Send invalid data from remote client\n\t\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson(\"invalid\"),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Reading the remote value should cause the validator to be called a second time and return undefined\n\t\t\t\t\tconst data2 = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(data2.value(), undefined, \"invalid data should return undefined\");\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t2,\n\t\t\t\t\t\t\"validator should be called twice\",\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tit(\"on .value() call when remote data changes from invalid to valid\", () => {\n\t\t\t\t\t// First send invalid data\n\t\t\t\t\tlet timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson(\"invalid\"),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Get the remote data and read it, verify that the validator is called once and returns undefined\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(remoteData.value(), undefined);\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1, \"first call count is wrong\");\n\n\t\t\t\t\t// Send valid data from remote client\n\t\t\t\t\ttimestamp += 10;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 4,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 100, y: 200, z: 300 }),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Reading the remote value should cause the validator to be called a second time and return valid data\n\t\t\t\t\tconst data2 = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\tdata2.value(),\n\t\t\t\t\t\t{ x: 100, y: 200, z: 300 },\n\t\t\t\t\t\t\"valid data should be returned\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t2,\n\t\t\t\t\t\t\"validator should be called twice\",\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tit(\"on .value() call when remote data changes from invalid to invalid\", () => {\n\t\t\t\t\t// First send invalid data\n\t\t\t\t\tlet timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson(\"invalid\"),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Get the remote data and read it, verify that the validator is called once and returns undefined\n\t\t\t\t\tconst remoteData = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(remoteData.value(), undefined);\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1, \"first call count is wrong\");\n\n\t\t\t\t\t// Send different invalid data from remote client\n\t\t\t\t\ttimestamp += 10;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latest\", {\n\t\t\t\t\t\t\t\"rev\": 4,\n\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\"value\": toOpaqueJson(\"also-invalid\"),\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Reading the remote value should cause the validator to be called a second time and still return undefined\n\t\t\t\t\tconst data2 = latest.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(data2.value(), undefined, \"invalid data should return undefined\");\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t2,\n\t\t\t\t\t\t\"validator should be called twice\",\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tdescribe(\"LatestMap with validation\", () => {\n\t\t\tlet latestMap: LatestMap<Point3D, `key${string}`>;\n\t\t\tlet keyValidatorCallExpectedCount: number;\n\n\t\t\tfunction keyValidatorFunction(key: string): key is `key${string}` {\n\t\t\t\tassert(\n\t\t\t\t\tkeyValidatorCallExpectedCount > 0,\n\t\t\t\t\t\"keyValidatorFunction should not be called at this time\",\n\t\t\t\t);\n\t\t\t\tkeyValidatorCallExpectedCount--;\n\t\t\t\treturn key.startsWith(\"key\");\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * This beforeEach sets up the presence workspace itself and gets a\n\t\t\t * reference to it.\n\t\t\t */\n\t\t\tbeforeEach(() => {\n\t\t\t\tkeyValidatorCallExpectedCount = 0;\n\n\t\t\t\t// workspace setup's initialization signal\n\t\t\t\truntime.signalsExpected.push([\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"Pres:DatastoreUpdate\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"sendTimestamp\": clock.now,\n\t\t\t\t\t\t\t\"avgLatency\": 10,\n\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t\t[initialLocalClientConnectionId]: {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": localAttendeeId,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\t\"latestMap\": {\n\t\t\t\t\t\t\t\t\t\t[localAttendeeId]: {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"key1\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": clock.now,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ \"x\": 0, \"y\": 0, \"z\": 0 }),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"key2\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": clock.now,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ \"x\": 0, \"y\": 0, \"z\": 0 }),\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t]);\n\n\t\t\t\tconst stateWorkspace = presence.states.getWorkspace(\"name:testWorkspace\", {\n\t\t\t\t\tlatestMap: StateFactory.latestMap({\n\t\t\t\t\t\tlocal: { \"key1\": { x: 0, y: 0, z: 0 }, \"key2\": { x: 0, y: 0, z: 0 } },\n\t\t\t\t\t\tvalidator: point3DValidatorFunction,\n\t\t\t\t\t\tkeyValidator: keyValidatorFunction,\n\t\t\t\t\t\tsettings: { allowableUpdateLatencyMs: 0 },\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\tlatestMap = stateWorkspace.states.latestMap;\n\t\t\t});\n\n\t\t\tfunction sendInvalidData(key: string = \"key1\"): void {\n\t\t\t\tkeyValidatorCallExpectedCount = 1;\n\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\tprocessSignal(\n\t\t\t\t\t[],\n\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latestMap\", {\n\t\t\t\t\t\t\"rev\": 2,\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t[key]: {\n\t\t\t\t\t\t\t\t\"rev\": 2,\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\t\"value\": toOpaqueJson(\"invalid\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tfalse,\n\t\t\t\t);\n\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\t\t\t}\n\n\t\t\tdescribe(\"no validator is called\", () => {\n\t\t\t\tbeforeEach(() => {\n\t\t\t\t\tvalidatorCallExpected = false;\n\t\t\t\t});\n\n\t\t\t\tit(\"when reading local key value\", () => {\n\t\t\t\t\t// Act\n\t\t\t\t\tconst localData = latestMap.local.get(\"key1\");\n\t\t\t\t\t// Verify\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t\t\t// double check local data\n\t\t\t\t\tassert.deepEqual(localData, { x: 0, y: 0, z: 0 });\n\t\t\t\t});\n\n\t\t\t\tit(\"when writing local key value\", () => {\n\t\t\t\t\t// Setup\n\t\t\t\t\truntime.signalsExpected.push([\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"type\": \"Pres:DatastoreUpdate\",\n\t\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\t\"sendTimestamp\": clock.now,\n\t\t\t\t\t\t\t\t\"avgLatency\": 10,\n\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t\t\t[initialLocalClientConnectionId]: {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime,\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": localAttendeeId,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\t\t\"latestMap\": {\n\t\t\t\t\t\t\t\t\t\t\t[localAttendeeId]: {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"key1\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": clock.now,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ \"x\": 0, \"y\": 1, \"z\": 2 }),\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t]);\n\n\t\t\t\t\t// Act\n\t\t\t\t\tlatestMap.local.set(\"key1\", { x: 0, y: 1, z: 2 });\n\t\t\t\t\t// Verify\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit(\"update with invalid key invokes key validator per key and does not raise events\", () => {\n\t\t\t\t// Setup\n\t\t\t\tfor (const event of [\n\t\t\t\t\t\"remoteUpdated\",\n\t\t\t\t\t\"remoteItemUpdated\",\n\t\t\t\t\t\"remoteItemRemoved\",\n\t\t\t\t] as const) {\n\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\tlatestMap.events.on(event, () => {\n\t\t\t\t\t\t\tassert.fail(`${event} event should not be raised for invalid key`);\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tkeyValidatorCallExpectedCount = 1;\n\t\t\t\t// Act\n\t\t\t\tsendInvalidData(\"invalidKey\");\n\t\t\t\t// Verify\n\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0); // all expected calls were made\n\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t});\n\n\t\t\t/**\n\t\t\t * Sets validator call expectations and gets remote value data.\n\t\t\t * @returns `latestMap.getRemote(remoteAttendee)`\n\t\t\t * @remarks\n\t\t\t * `validatorCallExpected` will be `false` and `keyValidatorCallExpectedCount`\n\t\t\t * will be `0` after the call.\n\t\t\t */\n\t\t\tfunction getRemoteValue(): ReturnType<typeof latestMap.getRemote> {\n\t\t\t\tvalidatorCallExpected = false;\n\t\t\t\tkeyValidatorCallExpectedCount = 3;\n\t\t\t\tconst remoteData = latestMap.getRemote(remoteAttendee);\n\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\t\t\t\treturn remoteData;\n\t\t\t}\n\n\t\t\tit(\".getRemote call invokes key validator per key but not value validator\", () => {\n\t\t\t\t// Setup and Act\n\t\t\t\tgetRemoteValue();\n\t\t\t\t// Verify\n\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0); // all expected calls were made\n\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t});\n\n\t\t\tdescribe(\"remote value map\", () => {\n\t\t\t\tit(\".get() does not call any validator\", () => {\n\t\t\t\t\t// Setup\n\t\t\t\t\tconst remoteData = getRemoteValue();\n\t\t\t\t\t// Act\n\t\t\t\t\tremoteData.get(\"key1\");\n\t\t\t\t\t// Verify\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0);\n\t\t\t\t});\n\n\t\t\t\tit(\".forEach() iteration does not call any validator\", () => {\n\t\t\t\t\t// Setup\n\t\t\t\t\tconst remoteData = getRemoteValue();\n\t\t\t\t\tlet counter = 0;\n\t\t\t\t\tconst expectedValues = [\n\t\t\t\t\t\t[\"key1\", { x: 1, y: 1, z: 1 }],\n\t\t\t\t\t\t[\"key2\", { x: 2, y: 2, z: 2 }],\n\t\t\t\t\t];\n\t\t\t\t\t// Act\n\t\t\t\t\t// eslint-disable-next-line unicorn/no-array-for-each -- forEach is being tested here\n\t\t\t\t\tremoteData.forEach((_value, key) => {\n\t\t\t\t\t\t// Verify\n\t\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 0, \"call count is wrong\");\n\t\t\t\t\t\tassert.equal(key, expectedValues[counter][0]);\n\t\t\t\t\t\tcounter++;\n\t\t\t\t\t});\n\t\t\t\t\t// Make sure forEach iterated through all keys\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tcounter,\n\t\t\t\t\t\texpectedValues.length,\n\t\t\t\t\t\t\"counter should match expected values length\",\n\t\t\t\t\t);\n\t\t\t\t});\n\n\t\t\t\tdescribe(\"value validator is called\", () => {\n\t\t\t\t\tfor (const { desc, setup, expectedValue } of [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"for valid value\",\n\t\t\t\t\t\t\tsetup: () => {},\n\t\t\t\t\t\t\texpectedValue: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"for invalid value\",\n\t\t\t\t\t\t\tsetup: sendInvalidData,\n\t\t\t\t\t\t\texpectedValue: undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t] as const) {\n\t\t\t\t\t\tit(`once when key.value() is called ${desc}`, () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tsetup();\n\t\t\t\t\t\t\tconst remoteData = getRemoteValue();\n\t\t\t\t\t\t\tvalidatorCallExpected = \"once\";\n\t\t\t\t\t\t\t// Act\n\t\t\t\t\t\t\trunValidatorTest({\n\t\t\t\t\t\t\t\tgetRemoteValue: () => remoteData.get(\"key1\")?.value(),\n\t\t\t\t\t\t\t\texpectedCallCount: 1,\n\t\t\t\t\t\t\t\texpectedValue,\n\t\t\t\t\t\t\t\tvalidatorFunction: point3DValidatorFunction,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(`only once for multiple key.value() calls in series and .value() always returned same result ${desc}`, () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tsetup();\n\t\t\t\t\t\t\tconst remoteData = getRemoteValue();\n\t\t\t\t\t\t\tvalidatorCallExpected = \"once\";\n\t\t\t\t\t\t\t// Act\n\t\t\t\t\t\t\trunMultipleCallsTest({\n\t\t\t\t\t\t\t\tgetRemoteValue: () => remoteData.get(\"key1\")?.value(),\n\t\t\t\t\t\t\t\texpectedValue,\n\t\t\t\t\t\t\t\tvalidatorFunction: point3DValidatorFunction,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(`exactly once for each value's .value() calls in .forEach() and .value() always returns same result ${desc}`, () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tsetup();\n\t\t\t\t\t\t\tconst remoteData = getRemoteValue();\n\t\t\t\t\t\t\tlet counter = 0;\n\t\t\t\t\t\t\tconst expectedValues = [\n\t\t\t\t\t\t\t\t// only key1 value might be altered by the setup function\n\t\t\t\t\t\t\t\t[\"key1\", expectedValue],\n\t\t\t\t\t\t\t\t// key2 value will always be the valid\n\t\t\t\t\t\t\t\t[\"key2\", { x: 2, y: 2, z: 2 }],\n\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t// Act\n\t\t\t\t\t\t\t// eslint-disable-next-line unicorn/no-array-for-each -- forEach is being tested here\n\t\t\t\t\t\t\tremoteData.forEach((value, key) => {\n\t\t\t\t\t\t\t\tassert.equal(key, expectedValues[counter][0]);\n\t\t\t\t\t\t\t\t// reset call expectations/count for each iteration\n\t\t\t\t\t\t\t\tvalidatorCallExpected = \"once\";\n\t\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount = 0;\n\n\t\t\t\t\t\t\t\t// Act - first call\n\t\t\t\t\t\t\t\tconst valueData = value?.value();\n\t\t\t\t\t\t\t\t// Verify\n\t\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\t\"validator was not called\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t// double check value\n\t\t\t\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\t\t\t\tvalueData,\n\t\t\t\t\t\t\t\t\texpectedValues[counter][1],\n\t\t\t\t\t\t\t\t\t`value at key \"${key}\" is wrong`,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Act - second call\n\t\t\t\t\t\t\t\t// Access value a second time; should not affect validator call count\n\t\t\t\t\t\t\t\tconst valueDataRedux = value?.value();\n\t\t\t\t\t\t\t\t// Verify\n\t\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\t\"validator was called a second time\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\t\tvalueDataRedux,\n\t\t\t\t\t\t\t\t\tvalueData,\n\t\t\t\t\t\t\t\t\t`value at key \"${key}\" is wrong`,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t// Make sure forEach iterated through all keys\n\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\tcounter,\n\t\t\t\t\t\t\t\texpectedValues.length,\n\t\t\t\t\t\t\t\t\"counter should match expected values length\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const { desc, setup, expectedInitialValue, newData, expectedValue } of [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"from valid to different valid value\",\n\t\t\t\t\t\t\tsetup: () => {},\n\t\t\t\t\t\t\texpectedInitialValue: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t\tnewData: { x: 4, y: 4, z: 4 },\n\t\t\t\t\t\t\texpectedValue: { x: 4, y: 4, z: 4 },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"from valid to same valid value\",\n\t\t\t\t\t\t\tsetup: () => {},\n\t\t\t\t\t\t\texpectedInitialValue: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t\tnewData: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t\texpectedValue: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"from valid to invalid value\",\n\t\t\t\t\t\t\tsetup: () => {},\n\t\t\t\t\t\t\texpectedInitialValue: { x: 1, y: 1, z: 1 },\n\t\t\t\t\t\t\tnewData: \"invalid\",\n\t\t\t\t\t\t\texpectedValue: undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"from invalid to valid value\",\n\t\t\t\t\t\t\tsetup: sendInvalidData,\n\t\t\t\t\t\t\texpectedInitialValue: undefined,\n\t\t\t\t\t\t\tnewData: { x: 4, y: 4, z: 4 },\n\t\t\t\t\t\t\texpectedValue: { x: 4, y: 4, z: 4 },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdesc: \"from invalid to invalid value\",\n\t\t\t\t\t\t\tsetup: sendInvalidData,\n\t\t\t\t\t\t\texpectedInitialValue: undefined,\n\t\t\t\t\t\t\tnewData: \"invalid\",\n\t\t\t\t\t\t\texpectedValue: undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t] as const) {\n\t\t\t\t\t\tit(`during .value() call after remote key data has changed ${desc}`, () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tsetup();\n\n\t\t\t\t\t\t\tconst originalMap = getRemoteValue();\n\t\t\t\t\t\t\tvalidatorCallExpected = \"once\";\n\t\t\t\t\t\t\t// Get the remote data and read it, expect that the validator is called once.\n\t\t\t\t\t\t\tconst key1Value = originalMap.get(\"key1\")?.value();\n\t\t\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1, \"first call count is wrong\");\n\t\t\t\t\t\t\tassert.deepEqual(key1Value, expectedInitialValue);\n\t\t\t\t\t\t\t// Reset call count for next verification\n\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount = 0;\n\n\t\t\t\t\t\t\t// Process updated key data from remote client\n\t\t\t\t\t\t\tkeyValidatorCallExpectedCount = 1;\n\t\t\t\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t\t\t[],\n\t\t\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latestMap\", {\n\t\t\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\"key1\": {\n\t\t\t\t\t\t\t\t\t\t\t\"rev\": 3,\n\t\t\t\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson(newData),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\n\t\t\t\t\t\t\t// Verify no call yet\n\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\"call count after update is wrong\",\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Reading the remote value should cause the validator to be\n\t\t\t\t\t\t\t// called since the data has been changed.\n\t\t\t\t\t\t\tconst updatedMap = getRemoteValue();\n\n\t\t\t\t\t\t\tvalidatorCallExpected = \"once\";\n\n\t\t\t\t\t\t\t// Act - read updated key value\n\t\t\t\t\t\t\tconst updatedKey1Value = updatedMap.get(\"key1\")?.value();\n\n\t\t\t\t\t\t\t// Verify\n\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"validator should be called twice\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\t\t\tupdatedKey1Value,\n\t\t\t\t\t\t\t\texpectedValue,\n\t\t\t\t\t\t\t\t\"updated remote key value is wrong\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// Note this block is after \"value validator is called\" as it is only valid when those tests are passing.\n\t\t\tdescribe(\"no validator is called\", () => {\n\t\t\t\tit(\"during .value() call for unchanged keys\", () => {\n\t\t\t\t\t// Setup\n\t\t\t\t\tkeyValidatorCallExpectedCount = 3;\n\t\t\t\t\tconst originalMap = latestMap.getRemote(remoteAttendee);\n\t\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\t\t\t\t\tvalidatorCallExpected = \"once\";\n\t\t\t\t\t// Read key1 value - should call validator once\n\t\t\t\t\tconst key1Value = originalMap.get(\"key1\")?.value();\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t1,\n\t\t\t\t\t\t\"validator should be called once for key1\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.deepEqual(key1Value, { x: 1, y: 1, z: 1 });\n\n\t\t\t\t\t// Update key2 (different key) with new data, keeping key1 unchanged\n\t\t\t\t\tkeyValidatorCallExpectedCount = 1;\n\t\t\t\t\tconst timestamp = clock.now - 15;\n\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t[],\n\t\t\t\t\t\tdatastoreUpdateSignal(timestamp, \"latestMap\", {\n\t\t\t\t\t\t\t\"rev\": 2,\n\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\"key2\": {\n\t\t\t\t\t\t\t\t\t\"rev\": 2,\n\t\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ \"x\": 4, \"y\": 4, \"z\": 4 }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\n\t\t\t\t\tconst updatedMap = getRemoteValue();\n\t\t\t\t\tconst key1Redux = updatedMap.get(\"key1\");\n\t\t\t\t\tassert.ok(key1Redux);\n\n\t\t\t\t\tassert.equal(keyValidatorCallExpectedCount, 0);\n\t\t\t\t\tassert.equal(point3DValidatorFunction.callCount, 1);\n\t\t\t\t\t// Act & Verify\n\t\t\t\t\t// Read key1 value (again) but from updated map - should NOT call validator again since key1 data hasn't changed\n\t\t\t\t\tconst key1ValueRedux = key1Redux.value();\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t1,\n\t\t\t\t\t\t\"validator should still be called only once for key1\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.strictEqual(key1ValueRedux, key1Value, \"key1 value should remain unchanged\");\n\n\t\t\t\t\t// Test verification\n\t\t\t\t\tvalidatorCallExpected = true;\n\t\t\t\t\tpoint3DValidatorFunction.callCount = 0;\n\t\t\t\t\t// key2 should have been updated; so, reading key2 value from\n\t\t\t\t\t// original map and updated map should both result in call\n\t\t\t\t\t// count increases. Also check for updated value.\n\t\t\t\t\tlet key2Value = originalMap.get(\"key2\")?.value();\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t1,\n\t\t\t\t\t\t\"validator should be called once for original key2 value read\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\tkey2Value,\n\t\t\t\t\t\t{ \"x\": 2, \"y\": 2, \"z\": 2 },\n\t\t\t\t\t\t\"key2 value from original map should be unchanged\",\n\t\t\t\t\t);\n\t\t\t\t\tkey2Value = updatedMap.get(\"key2\")?.value();\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tpoint3DValidatorFunction.callCount,\n\t\t\t\t\t\t2,\n\t\t\t\t\t\t\"validator should be called second time for updated key2 value read\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\tkey2Value,\n\t\t\t\t\t\t{ \"x\": 4, \"y\": 4, \"z\": 4 },\n\t\t\t\t\t\t\"key2 should have updated value\",\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
@@ -1,21 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.prepareDisconnectedPresence = exports.prepareConnectedPresence = exports.localAttendeeId = exports.initialLocalClientConnectionId = exports.generateBasicClientJoin = exports.createSpiedValidator = exports.createSpecificAttendeeId = exports.createInstanceOf = exports.connectionId1 = exports.attendeeId1 = exports.assertIdenticalTypes = exports.assertFinalExpectations = void 0;
8
- var test_utils_1 = require("@fluid-internal/presence-runtime/internal/test-utils");
9
- Object.defineProperty(exports, "assertFinalExpectations", { enumerable: true, get: function () { return test_utils_1.assertFinalExpectations; } });
10
- Object.defineProperty(exports, "assertIdenticalTypes", { enumerable: true, get: function () { return test_utils_1.assertIdenticalTypes; } });
11
- Object.defineProperty(exports, "attendeeId1", { enumerable: true, get: function () { return test_utils_1.attendeeId1; } });
12
- Object.defineProperty(exports, "connectionId1", { enumerable: true, get: function () { return test_utils_1.connectionId1; } });
13
- Object.defineProperty(exports, "createInstanceOf", { enumerable: true, get: function () { return test_utils_1.createInstanceOf; } });
14
- Object.defineProperty(exports, "createSpecificAttendeeId", { enumerable: true, get: function () { return test_utils_1.createSpecificAttendeeId; } });
15
- Object.defineProperty(exports, "createSpiedValidator", { enumerable: true, get: function () { return test_utils_1.createSpiedValidator; } });
16
- Object.defineProperty(exports, "generateBasicClientJoin", { enumerable: true, get: function () { return test_utils_1.generateBasicClientJoin; } });
17
- Object.defineProperty(exports, "initialLocalClientConnectionId", { enumerable: true, get: function () { return test_utils_1.initialLocalClientConnectionId; } });
18
- Object.defineProperty(exports, "localAttendeeId", { enumerable: true, get: function () { return test_utils_1.localAttendeeId; } });
19
- Object.defineProperty(exports, "prepareConnectedPresence", { enumerable: true, get: function () { return test_utils_1.prepareConnectedPresence; } });
20
- Object.defineProperty(exports, "prepareDisconnectedPresence", { enumerable: true, get: function () { return test_utils_1.prepareDisconnectedPresence; } });
21
- //# sourceMappingURL=testUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../../../src/states/test/testUtils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,mFAa8D;AAZ7D,qHAAA,uBAAuB,OAAA;AACvB,kHAAA,oBAAoB,OAAA;AACpB,yGAAA,WAAW,OAAA;AACX,2GAAA,aAAa,OAAA;AACb,8GAAA,gBAAgB,OAAA;AAChB,sHAAA,wBAAwB,OAAA;AACxB,kHAAA,oBAAoB,OAAA;AACpB,qHAAA,uBAAuB,OAAA;AACvB,4HAAA,8BAA8B,OAAA;AAC9B,6GAAA,eAAe,OAAA;AACf,sHAAA,wBAAwB,OAAA;AACxB,yHAAA,2BAA2B,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type {\n\tInboundPresenceSignalMessage,\n\tProcessSignalFunction,\n} from \"@fluid-internal/presence-runtime/internal/test-utils\";\nexport {\n\tassertFinalExpectations,\n\tassertIdenticalTypes,\n\tattendeeId1,\n\tconnectionId1,\n\tcreateInstanceOf,\n\tcreateSpecificAttendeeId,\n\tcreateSpiedValidator,\n\tgenerateBasicClientJoin,\n\tinitialLocalClientConnectionId,\n\tlocalAttendeeId,\n\tprepareConnectedPresence,\n\tprepareDisconnectedPresence,\n} from \"@fluid-internal/presence-runtime/internal/test-utils\";\n"]}
@@ -1,175 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.MockEphemeralRuntime = exports.initialLocalClientConnectionId = void 0;
8
- const node_assert_1 = require("node:assert");
9
- const internal_1 = require("@fluidframework/test-runtime-utils/internal");
10
- const internal_2 = require("@fluidframework/test-utils/internal");
11
- /**
12
- * Mock {@link ClientConnectionId} for the local client in tests.
13
- */
14
- exports.initialLocalClientConnectionId = "localClient";
15
- function buildClientDataArray(clientIds, numWriteClients) {
16
- const clients = [];
17
- for (const [index, clientId] of clientIds.entries()) {
18
- // eslint-disable-next-line unicorn/prefer-code-point
19
- const stringId = String.fromCharCode(index + 65);
20
- const name = stringId.repeat(10);
21
- const userId = `${name}@microsoft.com`;
22
- const user = {
23
- id: userId,
24
- };
25
- clients.push([
26
- clientId,
27
- {
28
- mode: index < numWriteClients ? "write" : "read",
29
- details: { capabilities: { interactive: true } },
30
- permission: [],
31
- user,
32
- scopes: [],
33
- },
34
- ]);
35
- }
36
- return clients;
37
- }
38
- /**
39
- * Creates a mock {@link @fluidframework/protocol-definitions#IQuorumClients} for testing.
40
- */
41
- function makeMockQuorum(clients) {
42
- return new internal_1.MockQuorumClients(...clients
43
- .filter(([, client]) => client.mode === "write")
44
- .map(([clientId, client], index) => [
45
- clientId,
46
- { client, sequenceNumber: 10 * index },
47
- ]));
48
- }
49
- /**
50
- * Creates a mock {@link @fluidframework/container-definitions#IAudience} for testing.
51
- */
52
- function makeMockAudience(clients) {
53
- const audience = new internal_1.MockAudience();
54
- for (const [clientId, client] of clients) {
55
- audience.addMember(clientId, client);
56
- }
57
- return audience;
58
- }
59
- /**
60
- * Mock ephemeral runtime for testing
61
- */
62
- class MockEphemeralRuntime {
63
- isSupportedEvent(event) {
64
- return event in this.listeners;
65
- }
66
- constructor(logger = new internal_2.EventAndErrorTrackingLogger(), signalsExpected = []) {
67
- this.signalsExpected = signalsExpected;
68
- this.joined = false;
69
- this.listeners = {
70
- joined: [],
71
- disconnected: [],
72
- };
73
- // #region IEphemeralRuntime
74
- this.getJoinedStatus = () => {
75
- return this.joined ? "joinedForReading" : "disconnected";
76
- };
77
- this.getClientId = () => this.clientId;
78
- this.getQuorum = () => this.quorum;
79
- this.getAudience = () => this.audience;
80
- this.submitSignal = (...args) => {
81
- if (this.signalsExpected.length === 0) {
82
- throw new Error(`Unexpected signal: ${JSON.stringify(args)}`);
83
- }
84
- const expected = this.signalsExpected.shift();
85
- node_assert_1.strict.deepStrictEqual(args, expected, "Unexpected signal");
86
- };
87
- this.supportedFeatures = new Set(["submit_signals_v2"]);
88
- this.logger = logger;
89
- const numWriteClients = 6;
90
- const clientsData = buildClientDataArray([
91
- "client0",
92
- "client1",
93
- exports.initialLocalClientConnectionId,
94
- "client3",
95
- "client4",
96
- "client5",
97
- "client6",
98
- "client7",
99
- ], numWriteClients);
100
- this.quorum = makeMockQuorum(clientsData);
101
- this.audience = makeMockAudience(clientsData);
102
- this.events = {
103
- on: (event, listener) => {
104
- if (!this.isSupportedEvent(event)) {
105
- throw new Error(`Event ${event} is not supported`);
106
- }
107
- // Switch to allowing a single listener as commented when
108
- // implementation uses a single "joined" listener.
109
- // if (this.listeners[event]) {
110
- // throw new Error(`Event ${event} already has a listener`);
111
- // }
112
- // this.listeners[event] = listener;
113
- if (this.listeners[event].length > 1) {
114
- throw new Error(`Event ${event} already has multiple listeners`);
115
- }
116
- this.listeners[event].push(listener);
117
- return this;
118
- },
119
- off: (
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- ) => {
122
- throw new Error("IEphemeralRuntime.off method not implemented.");
123
- },
124
- };
125
- }
126
- assertAllSignalsSubmitted() {
127
- node_assert_1.strict.strictEqual(this.signalsExpected.length, 0, `Missing signals [\n${this.signalsExpected
128
- .map(([m]) => `\t{ type: ${m.type}, content: ${JSON.stringify(m.content, undefined, "\t")}, targetClientId: ${m.targetClientId} }`)
129
- .join(",\n\t")}\n]`);
130
- }
131
- /**
132
- * Removes a member from both audience and quorum.
133
- */
134
- removeMember(clientId) {
135
- const client = this.audience.getMember(clientId);
136
- (0, node_assert_1.strict)(client !== undefined, `Attempting to remove unknown connection: ${clientId}`);
137
- if (client.mode === "write") {
138
- this.quorum.removeMember(clientId);
139
- }
140
- this.audience.removeMember(clientId);
141
- }
142
- connect(clientId, oldClientId) {
143
- // during connect audience is refreshed - snapshot current members
144
- const members = this.audience.getMembers();
145
- this.audience.setCurrentClientId(clientId);
146
- this.clientId = clientId;
147
- this.joined = true;
148
- for (const listener of this.listeners.joined) {
149
- listener({ clientId, canWrite: false });
150
- }
151
- // simulate expected "clear"
152
- for (const [memberClientId] of members) {
153
- (0, node_assert_1.strict)(memberClientId !== clientId, "`connect` should not use clientId already in audience");
154
- this.audience.removeMember(memberClientId);
155
- }
156
- // restore members
157
- for (const [memberClientId, client] of members) {
158
- if (memberClientId !== oldClientId) {
159
- this.audience.addMember(memberClientId, client);
160
- }
161
- }
162
- // finally add new connection to audience
163
- for (const [newClientId, newMember] of buildClientDataArray([clientId], 1)) {
164
- this.audience.addMember(newClientId, newMember);
165
- }
166
- }
167
- disconnect() {
168
- this.joined = false;
169
- for (const listener of this.listeners.disconnected) {
170
- listener();
171
- }
172
- }
173
- }
174
- exports.MockEphemeralRuntime = MockEphemeralRuntime;
175
- //# sourceMappingURL=mockEphemeralRuntime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mockEphemeralRuntime.js","sourceRoot":"","sources":["../../src/test/mockEphemeralRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type { ClientConnectionId } from \"@fluid-internal/presence-definitions\";\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IClient, ISequencedClient } from \"@fluidframework/driver-definitions\";\nimport { MockAudience, MockQuorumClients } from \"@fluidframework/test-runtime-utils/internal\";\nimport { EventAndErrorTrackingLogger } from \"@fluidframework/test-utils/internal\";\n\nimport type { IEphemeralRuntime } from \"@fluid-internal/presence-runtime/internal/test\";\n\n/**\n * Mock {@link ClientConnectionId} for the local client in tests.\n */\nexport const initialLocalClientConnectionId =\n\t\"localClient\" as const satisfies ClientConnectionId;\n\ntype ClientData = [string, IClient];\n\nfunction buildClientDataArray(clientIds: string[], numWriteClients: number): ClientData[] {\n\tconst clients: ClientData[] = [];\n\tfor (const [index, clientId] of clientIds.entries()) {\n\t\t// eslint-disable-next-line unicorn/prefer-code-point\n\t\tconst stringId = String.fromCharCode(index + 65);\n\t\tconst name = stringId.repeat(10);\n\t\tconst userId = `${name}@microsoft.com`;\n\t\tconst user = {\n\t\t\tid: userId,\n\t\t};\n\t\tclients.push([\n\t\t\tclientId,\n\t\t\t{\n\t\t\t\tmode: index < numWriteClients ? \"write\" : \"read\",\n\t\t\t\tdetails: { capabilities: { interactive: true } },\n\t\t\t\tpermission: [],\n\t\t\t\tuser,\n\t\t\t\tscopes: [],\n\t\t\t},\n\t\t]);\n\t}\n\treturn clients;\n}\n\n/**\n * Creates a mock {@link @fluidframework/protocol-definitions#IQuorumClients} for testing.\n */\nfunction makeMockQuorum(clients: ClientData[]): MockQuorumClients {\n\treturn new MockQuorumClients(\n\t\t...clients\n\t\t\t.filter(([, client]) => client.mode === \"write\")\n\t\t\t.map(([clientId, client], index): [string, Partial<ISequencedClient>] => [\n\t\t\t\tclientId,\n\t\t\t\t{ client, sequenceNumber: 10 * index },\n\t\t\t]),\n\t);\n}\n\n/**\n * Creates a mock {@link @fluidframework/container-definitions#IAudience} for testing.\n */\nfunction makeMockAudience(clients: ClientData[]): MockAudience {\n\tconst audience = new MockAudience();\n\tfor (const [clientId, client] of clients) {\n\t\taudience.addMember(clientId, client);\n\t}\n\treturn audience;\n}\n\n/**\n * Mock ephemeral runtime for testing\n */\nexport class MockEphemeralRuntime implements IEphemeralRuntime {\n\tpublic clientId: string | undefined;\n\tpublic joined: boolean = false;\n\tpublic logger: ITelemetryBaseLogger;\n\tpublic readonly quorum: MockQuorumClients;\n\tpublic readonly audience: MockAudience;\n\n\tpublic readonly listeners: {\n\t\tjoined: ((props: { clientId: ClientConnectionId; canWrite: boolean }) => void)[];\n\t\tdisconnected: (() => void)[];\n\t} = {\n\t\tjoined: [],\n\t\tdisconnected: [],\n\t};\n\n\tprivate isSupportedEvent(event: string): event is keyof typeof this.listeners {\n\t\treturn event in this.listeners;\n\t}\n\n\tpublic constructor(\n\t\tlogger: ITelemetryBaseLogger = new EventAndErrorTrackingLogger(),\n\t\tpublic readonly signalsExpected: Parameters<IEphemeralRuntime[\"submitSignal\"]>[] = [],\n\t) {\n\t\tthis.logger = logger;\n\n\t\tconst numWriteClients = 6;\n\t\tconst clientsData = buildClientDataArray(\n\t\t\t[\n\t\t\t\t\"client0\",\n\t\t\t\t\"client1\",\n\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\"client3\",\n\t\t\t\t\"client4\",\n\t\t\t\t\"client5\",\n\t\t\t\t\"client6\",\n\t\t\t\t\"client7\",\n\t\t\t],\n\t\t\tnumWriteClients,\n\t\t);\n\t\tthis.quorum = makeMockQuorum(clientsData);\n\t\tthis.audience = makeMockAudience(clientsData);\n\t\tthis.events = {\n\t\t\ton: (\n\t\t\t\tevent: string,\n\t\t\t\tlistener: (...args: any[]) => void,\n\t\t\t\t// Events style eventing does not lend itself to union that\n\t\t\t\t// IEphemeralRuntime is derived from, so we are using `any` here\n\t\t\t\t// but meet the intent of the interface.\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t): any => {\n\t\t\t\tif (!this.isSupportedEvent(event)) {\n\t\t\t\t\tthrow new Error(`Event ${event} is not supported`);\n\t\t\t\t}\n\t\t\t\t// Switch to allowing a single listener as commented when\n\t\t\t\t// implementation uses a single \"joined\" listener.\n\t\t\t\t// if (this.listeners[event]) {\n\t\t\t\t// \tthrow new Error(`Event ${event} already has a listener`);\n\t\t\t\t// }\n\t\t\t\t// this.listeners[event] = listener;\n\t\t\t\tif (this.listeners[event].length > 1) {\n\t\t\t\t\tthrow new Error(`Event ${event} already has multiple listeners`);\n\t\t\t\t}\n\t\t\t\tthis.listeners[event].push(listener);\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\toff: (\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t): any => {\n\t\t\t\tthrow new Error(\"IEphemeralRuntime.off method not implemented.\");\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic assertAllSignalsSubmitted(): void {\n\t\tassert.strictEqual(\n\t\t\tthis.signalsExpected.length,\n\t\t\t0,\n\t\t\t`Missing signals [\\n${this.signalsExpected\n\t\t\t\t.map(\n\t\t\t\t\t([m]) =>\n\t\t\t\t\t\t`\\t{ type: ${m.type}, content: ${JSON.stringify(m.content, undefined, \"\\t\")}, targetClientId: ${m.targetClientId} }`,\n\t\t\t\t)\n\t\t\t\t.join(\",\\n\\t\")}\\n]`,\n\t\t);\n\t}\n\n\t/**\n\t * Removes a member from both audience and quorum.\n\t */\n\tpublic removeMember(clientId: ClientConnectionId): void {\n\t\tconst client = this.audience.getMember(clientId);\n\t\tassert(client !== undefined, `Attempting to remove unknown connection: ${clientId}`);\n\t\tif (client.mode === \"write\") {\n\t\t\tthis.quorum.removeMember(clientId);\n\t\t}\n\t\tthis.audience.removeMember(clientId);\n\t}\n\n\tpublic connect(clientId: string, oldClientId: string | undefined): void {\n\t\t// during connect audience is refreshed - snapshot current members\n\t\tconst members = this.audience.getMembers();\n\n\t\tthis.audience.setCurrentClientId(clientId);\n\n\t\tthis.clientId = clientId;\n\t\tthis.joined = true;\n\t\tfor (const listener of this.listeners.joined) {\n\t\t\tlistener({ clientId, canWrite: false });\n\t\t}\n\n\t\t// simulate expected \"clear\"\n\t\tfor (const [memberClientId] of members) {\n\t\t\tassert(\n\t\t\t\tmemberClientId !== clientId,\n\t\t\t\t\"`connect` should not use clientId already in audience\",\n\t\t\t);\n\t\t\tthis.audience.removeMember(memberClientId);\n\t\t}\n\t\t// restore members\n\t\tfor (const [memberClientId, client] of members) {\n\t\t\tif (memberClientId !== oldClientId) {\n\t\t\t\tthis.audience.addMember(memberClientId, client);\n\t\t\t}\n\t\t}\n\t\t// finally add new connection to audience\n\t\tfor (const [newClientId, newMember] of buildClientDataArray([clientId], 1)) {\n\t\t\tthis.audience.addMember(newClientId, newMember);\n\t\t}\n\t}\n\n\tpublic disconnect(): void {\n\t\tthis.joined = false;\n\t\tfor (const listener of this.listeners.disconnected) {\n\t\t\tlistener();\n\t\t}\n\t}\n\n\t// #region IEphemeralRuntime\n\tpublic getJoinedStatus = (): ReturnType<IEphemeralRuntime[\"getJoinedStatus\"]> => {\n\t\treturn this.joined ? \"joinedForReading\" : \"disconnected\";\n\t};\n\tpublic getClientId = (): ReturnType<IEphemeralRuntime[\"getClientId\"]> => this.clientId;\n\n\tpublic events: IEphemeralRuntime[\"events\"];\n\n\tpublic getQuorum: () => ReturnType<IEphemeralRuntime[\"getQuorum\"]> = () => this.quorum;\n\tpublic getAudience: () => ReturnType<IEphemeralRuntime[\"getAudience\"]> = () => this.audience;\n\n\tpublic submitSignal: IEphemeralRuntime[\"submitSignal\"] = (...args: unknown[]) => {\n\t\tif (this.signalsExpected.length === 0) {\n\t\t\tthrow new Error(`Unexpected signal: ${JSON.stringify(args)}`);\n\t\t}\n\t\tconst expected = this.signalsExpected.shift();\n\t\tassert.deepStrictEqual(args, expected, \"Unexpected signal\");\n\t};\n\n\tpublic supportedFeatures: ReadonlySet<string> = new Set([\"submit_signals_v2\"]);\n\n\t// #endregion\n}\n"]}
@@ -1,262 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.createSpiedValidator = exports.assertFinalExpectations = exports.prepareDisconnectedPresence = exports.prepareConnectedPresence = exports.generateBasicClientJoin = exports.localAttendeeId = exports.connectionId1 = exports.attendeeId1 = exports.createSpecificAttendeeId = exports.createInstanceOf = exports.assertIdenticalTypes = void 0;
8
- const internal_1 = require("@fluidframework/test-utils/internal");
9
- const sinon_1 = require("sinon");
10
- const test_1 = require("@fluid-internal/presence-runtime/internal/test");
11
- const mockEphemeralRuntime_js_1 = require("./mockEphemeralRuntime.js");
12
- /**
13
- * Use to compile-time assert types of two variables are identical.
14
- */
15
- function assertIdenticalTypes(_actual, _expected) {
16
- return undefined;
17
- }
18
- exports.assertIdenticalTypes = assertIdenticalTypes;
19
- /**
20
- * Creates a non-viable (`undefined`) instance of type T to be used for type checking.
21
- */
22
- function createInstanceOf() {
23
- return undefined;
24
- }
25
- exports.createInstanceOf = createInstanceOf;
26
- /**
27
- * Forms {@link AttendeeId} for a specific attendee
28
- */
29
- function createSpecificAttendeeId(id) {
30
- return id;
31
- }
32
- exports.createSpecificAttendeeId = createSpecificAttendeeId;
33
- /**
34
- * Mock {@link AttendeeId}.
35
- */
36
- exports.attendeeId1 = createSpecificAttendeeId("attendeeId-1");
37
- /**
38
- * Mock {@link ClientConnectionId}.
39
- */
40
- exports.connectionId1 = "client1";
41
- /**
42
- * Mock {@link AttendeeId} for the local client in tests.
43
- */
44
- exports.localAttendeeId = createSpecificAttendeeId("localAttendeeId");
45
- /**
46
- * Generates expected inbound join signal for a client that was initialized while connected.
47
- */
48
- function generateBasicClientJoin(fixedTime, { attendeeId = exports.localAttendeeId, clientConnectionId = mockEphemeralRuntime_js_1.initialLocalClientConnectionId, updateProviders = ["client0", "client1", "client3"], connectionOrder = 0, averageLatency = 0, priorClientToSessionId = {}, }) {
49
- return {
50
- type: "Pres:ClientJoin",
51
- content: {
52
- "avgLatency": averageLatency,
53
- "data": {
54
- "system:presence": {
55
- "clientToSessionId": {
56
- ...priorClientToSessionId,
57
- [clientConnectionId]: {
58
- "rev": connectionOrder,
59
- "timestamp": fixedTime,
60
- "value": attendeeId,
61
- },
62
- },
63
- },
64
- },
65
- "sendTimestamp": fixedTime,
66
- updateProviders,
67
- },
68
- clientId: clientConnectionId,
69
- };
70
- }
71
- exports.generateBasicClientJoin = generateBasicClientJoin;
72
- /**
73
- * Creates a processSignal wrapper function for a presence manager.
74
- */
75
- function createProcessSignal(presence) {
76
- return (addressChain, signalMessage, local) => {
77
- // Pass on to presence manager, but first clone the message to avoid
78
- // possibility of Presence mutating the original message which often
79
- // contains reference to general (shared) test data.
80
- // Additionally JSON.parse(JSON.stringify(signalMessage)) is used to
81
- // ensure only regular JSON-serializable data is passed to Presence.
82
- // In production environment, the message is always extracted from
83
- // the network and Presence can safely mutate it.
84
- presence.processSignal(addressChain,
85
- // eslint-disable-next-line unicorn/prefer-structured-clone -- not structural clone, but filters to JSON-serializable data
86
- JSON.parse(JSON.stringify(signalMessage)), local);
87
- };
88
- }
89
- /**
90
- * Calculates update providers based on current audience members.
91
- */
92
- function calculateUpdateProviders(runtime, clientConnectionId) {
93
- // This logic needs to be kept in sync with datastore manager.
94
- // From PresenceDatastoreManager.getAudienceInformation:
95
- const members = runtime.audience.getMembers();
96
- members.delete(clientConnectionId);
97
- const all = new Set();
98
- const writers = new Set();
99
- for (const [id, client] of members) {
100
- if (client.details.capabilities.interactive) {
101
- all.add(id);
102
- if (client.mode === "write") {
103
- writers.add(id);
104
- }
105
- }
106
- }
107
- // From PresenceDatastoreManager.joinSession:
108
- const updateProviders = [...(writers.size > 0 ? writers : all)];
109
- if (updateProviders.length > 3) {
110
- updateProviders.length = 3;
111
- }
112
- return updateProviders;
113
- }
114
- /**
115
- * Prepares the expected client join signal and calculates update providers.
116
- */
117
- function prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock) {
118
- const updateProviders = calculateUpdateProviders(runtime, clientConnectionId);
119
- const expectedClientJoin = generateBasicClientJoin(clock.now, {
120
- attendeeId,
121
- clientConnectionId,
122
- updateProviders,
123
- });
124
- delete expectedClientJoin.clientId;
125
- runtime.signalsExpected.push([expectedClientJoin]);
126
- return { expectedClientJoin, updateProviders };
127
- }
128
- /**
129
- * Processes the local join signal and sends a fake join response.
130
- */
131
- function processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, latency) {
132
- // Pass a little time (to mimic reality)
133
- clock.tick(latency);
134
- // Return the [local] join signal
135
- processSignal([], { ...expectedClientJoin, clientId: clientConnectionId }, true);
136
- if (updateProviders.length > 0) {
137
- // Pass time (to mimic likely response)
138
- clock.tick(test_1.broadcastJoinResponseDelaysMs.namedResponder + 20);
139
- // Send a fake join response
140
- // There are no other attendees in the session (not realistic) but this
141
- // convinces the presence manager that it now has full knowledge, which
142
- // enables it to respond to other's join requests accurately.
143
- processSignal([], {
144
- type: "Pres:DatastoreUpdate",
145
- content: {
146
- ...expectedClientJoin.content,
147
- isComplete: true,
148
- joinResponseFor: [clientConnectionId],
149
- },
150
- clientId: updateProviders[0],
151
- }, false);
152
- }
153
- }
154
- /**
155
- * The simulated local average latency used in test helpers.
156
- */
157
- const localAvgLatency = 10;
158
- /**
159
- * Creates presence manager for testing.
160
- */
161
- function createPresence(runtime, attendeeId, logger) {
162
- logger.registerExpectedEvent({ eventName: "Presence:PresenceInstantiated" });
163
- const presence = (0, test_1.createPresenceManager)(runtime, attendeeId);
164
- const processSignal = createProcessSignal(presence);
165
- // Validate expectations post initialization to make sure logger
166
- // and runtime are left in a clean expectation state.
167
- const logErrors = (0, internal_1.getUnexpectedLogErrorException)(logger);
168
- if (logErrors) {
169
- throw logErrors;
170
- }
171
- return { presence, processSignal };
172
- }
173
- /**
174
- * Prepares an instance of presence as it would be if initialized while connected.
175
- *
176
- * @param runtime - the mock runtime
177
- * @param attendeeId - the client session id given to presence
178
- * @param clientConnectionId - the client connection id
179
- * @param clock - the fake timer.
180
- * @param logger - logger to track telemetry events
181
- */
182
- function prepareConnectedPresence(runtime, attendeeId, clientConnectionId, clock, logger) {
183
- // Set runtime to connected state
184
- runtime.clientId = clientConnectionId;
185
- runtime.joined = true;
186
- const { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock);
187
- const { presence, processSignal } = createPresence(runtime, attendeeId, logger);
188
- runtime.assertAllSignalsSubmitted();
189
- processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, localAvgLatency);
190
- return {
191
- presence,
192
- processSignal,
193
- localAvgLatency,
194
- };
195
- }
196
- exports.prepareConnectedPresence = prepareConnectedPresence;
197
- /**
198
- * Prepares an instance of presence in a disconnected state.
199
- *
200
- * @remarks
201
- * Use this helper when you need to test events that occur during the initial
202
- * connection, such as `attendeeConnected` for the local client.
203
- *
204
- * @param runtime - the mock runtime
205
- * @param attendeeId - the client session id given to presence
206
- * @param clientConnectionId - the client connection id to use when connecting
207
- * @param clock - the fake timer
208
- * @param logger - logger to track telemetry events
209
- */
210
- function prepareDisconnectedPresence(runtime, attendeeId, clientConnectionId, clock, logger) {
211
- // Ensure runtime is in disconnected state
212
- runtime.clientId = undefined;
213
- runtime.joined = false;
214
- // Remove client connection id from audience if present
215
- if (runtime.audience.getMember(clientConnectionId) !== undefined) {
216
- runtime.removeMember(clientConnectionId);
217
- }
218
- const { presence, processSignal } = createPresence(runtime, attendeeId, logger);
219
- const connect = () => {
220
- const { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock);
221
- // Simulate connection
222
- runtime.connect(clientConnectionId, undefined);
223
- // Validate signal was submitted
224
- runtime.assertAllSignalsSubmitted();
225
- processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, localAvgLatency);
226
- };
227
- return {
228
- presence,
229
- processSignal,
230
- connect,
231
- localAvgLatency,
232
- };
233
- }
234
- exports.prepareDisconnectedPresence = prepareDisconnectedPresence;
235
- /**
236
- * Asserts that all expected telemetry and signals were sent.
237
- */
238
- function assertFinalExpectations(runtime, logger) {
239
- // Make sure all expected events were logged and there are no unexpected errors.
240
- const logErrors = (0, internal_1.getUnexpectedLogErrorException)(logger);
241
- if (logErrors) {
242
- throw logErrors;
243
- }
244
- // Make sure all expected signals were sent.
245
- runtime.assertAllSignalsSubmitted();
246
- }
247
- exports.assertFinalExpectations = assertFinalExpectations;
248
- /**
249
- * A null validator (one that does nothing) for a given type T. It simply casts the value to
250
- * `JsonDeserialized<T>`.
251
- */
252
- const nullValidator = (data) => {
253
- return data;
254
- };
255
- /**
256
- * Creates a spied validator for test purposes.
257
- *
258
- * @param validatorFunction - A {@link StateSchemaValidator} to wrap in a spy.
259
- */
260
- const createSpiedValidator = (validatorFunction = (nullValidator)) => (0, sinon_1.spy)(validatorFunction);
261
- exports.createSpiedValidator = createSpiedValidator;
262
- //# sourceMappingURL=testUtils.js.map