@fluidframework/test-utils 2.31.1 → 2.33.0-333010

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 (38) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/packageVersion.d.ts +1 -1
  7. package/dist/packageVersion.d.ts.map +1 -1
  8. package/dist/packageVersion.js +1 -1
  9. package/dist/packageVersion.js.map +1 -1
  10. package/dist/testFluidObject.d.ts +23 -10
  11. package/dist/testFluidObject.d.ts.map +1 -1
  12. package/dist/testFluidObject.js +22 -19
  13. package/dist/testFluidObject.js.map +1 -1
  14. package/dist/testFluidObjectInternal.d.ts +50 -0
  15. package/dist/testFluidObjectInternal.d.ts.map +1 -0
  16. package/dist/testFluidObjectInternal.js +78 -0
  17. package/dist/testFluidObjectInternal.js.map +1 -0
  18. package/lib/index.d.ts +2 -1
  19. package/lib/index.d.ts.map +1 -1
  20. package/lib/index.js +1 -0
  21. package/lib/index.js.map +1 -1
  22. package/lib/packageVersion.d.ts +1 -1
  23. package/lib/packageVersion.d.ts.map +1 -1
  24. package/lib/packageVersion.js +1 -1
  25. package/lib/packageVersion.js.map +1 -1
  26. package/lib/testFluidObject.d.ts +23 -10
  27. package/lib/testFluidObject.d.ts.map +1 -1
  28. package/lib/testFluidObject.js +22 -19
  29. package/lib/testFluidObject.js.map +1 -1
  30. package/lib/testFluidObjectInternal.d.ts +50 -0
  31. package/lib/testFluidObjectInternal.d.ts.map +1 -0
  32. package/lib/testFluidObjectInternal.js +74 -0
  33. package/lib/testFluidObjectInternal.js.map +1 -0
  34. package/package.json +24 -23
  35. package/src/index.ts +3 -0
  36. package/src/packageVersion.ts +1 -1
  37. package/src/testFluidObject.ts +61 -28
  38. package/src/testFluidObjectInternal.ts +110 -0
@@ -3,7 +3,12 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { IFluidHandle, IRequest, IResponse } from "@fluidframework/core-interfaces";
6
+ import {
7
+ IFluidHandle,
8
+ IRequest,
9
+ IResponse,
10
+ type IFluidLoadable,
11
+ } from "@fluidframework/core-interfaces";
7
12
  import { assert } from "@fluidframework/core-utils/internal";
8
13
  import {
9
14
  FluidDataStoreRuntime,
@@ -21,13 +26,18 @@ import {
21
26
  IFluidDataStoreFactory,
22
27
  } from "@fluidframework/runtime-definitions/internal";
23
28
  import { create404Response } from "@fluidframework/runtime-utils/internal";
29
+ import type { ISharedObject } from "@fluidframework/shared-object-base/internal";
24
30
 
25
31
  import { ITestFluidObject } from "./interfaces.js";
26
32
 
27
33
  /**
28
- * A test Fluid object that will create a shared object for each key-value pair in the factoryEntries passed to load.
34
+ * A test Fluid object that will create a shared object for each key-value pair in the initialSharedObjectsFactories passed to load.
29
35
  * The shared objects can be retrieved by passing the key of the entry to getSharedObject.
30
36
  * It exposes the IFluidDataStoreContext and IFluidDataStoreRuntime.
37
+ * @privateRemarks
38
+ * TODO:
39
+ * Usage of this outside this repo (via ITestFluidObject) should probably be phased out.
40
+ * Once thats done, ITestFluidObject can be made internal and this class can be replaced with the simplified TestFluidObjectInternal.
31
41
  * @internal
32
42
  */
33
43
  export class TestFluidObject implements ITestFluidObject {
@@ -39,28 +49,28 @@ export class TestFluidObject implements ITestFluidObject {
39
49
  return this;
40
50
  }
41
51
 
42
- public get handle(): IFluidHandle<this> {
43
- return this.innerHandle;
44
- }
52
+ public readonly handle: IFluidHandle<this>;
45
53
 
46
54
  public root!: ISharedMap;
47
- private readonly innerHandle: IFluidHandle<this>;
48
55
  private initializationPromise: Promise<void> | undefined;
49
56
 
50
57
  /**
51
58
  * Creates a new TestFluidObject.
52
59
  * @param runtime - The data store runtime.
53
60
  * @param context - The data store context.
54
- * @param factoryEntries - A list of id to IChannelFactory mapping. For each item in the list,
61
+ * @param initialSharedObjectsFactories - A list of id to IChannelFactory mapping. For each item in the list,
55
62
  * a shared object is created which can be retrieved by calling getSharedObject() with the id;
56
63
  */
57
64
  constructor(
58
65
  public readonly runtime: IFluidDataStoreRuntime,
59
66
  public readonly channel: IFluidDataStoreChannel,
60
67
  public readonly context: IFluidDataStoreContext,
61
- private readonly factoryEntriesMap: Map<string, IChannelFactory>,
68
+ private readonly initialSharedObjectsFactories: ReadonlyMap<
69
+ string,
70
+ IChannelFactory<ISharedObject>
71
+ >,
62
72
  ) {
63
- this.innerHandle = new FluidObjectHandle(this, "", runtime.objectsRoutingContext);
73
+ this.handle = new FluidObjectHandle(this, "", runtime.objectsRoutingContext);
64
74
  }
65
75
 
66
76
  /**
@@ -68,15 +78,15 @@ export class TestFluidObject implements ITestFluidObject {
68
78
  * @param id - The id of the shared object to retrieve.
69
79
  */
70
80
  public async getSharedObject<T = any>(id: string): Promise<T> {
71
- if (this.factoryEntriesMap === undefined) {
81
+ if (this.initialSharedObjectsFactories === undefined) {
72
82
  throw new Error("Shared objects were not provided during creation.");
73
83
  }
74
84
 
75
- if (this.factoryEntriesMap.has(id)) {
85
+ if (this.initialSharedObjectsFactories.has(id)) {
76
86
  const handle = this.root.get<IFluidHandle<T>>(id);
77
87
  if (handle === undefined) {
78
88
  throw new Error(
79
- `Shared object with id '${id}' is in factoryEntriesMap but not found under root.`,
89
+ `Shared object with id '${id}' is in initialSharedObjectsFactories but not found under root.`,
80
90
  );
81
91
  }
82
92
  return handle.get();
@@ -96,10 +106,12 @@ export class TestFluidObject implements ITestFluidObject {
96
106
  if (!existing) {
97
107
  this.root = SharedMap.create(this.runtime, "root");
98
108
 
99
- this.factoryEntriesMap.forEach((sharedObjectFactory: IChannelFactory, key: string) => {
100
- const sharedObject = this.runtime.createChannel(key, sharedObjectFactory.type);
101
- this.root.set(key, sharedObject.handle);
102
- });
109
+ this.initialSharedObjectsFactories.forEach(
110
+ (sharedObjectFactory: IChannelFactory, key: string) => {
111
+ const sharedObject = this.runtime.createChannel(key, sharedObjectFactory.type);
112
+ this.root.set(key, sharedObject.handle);
113
+ },
114
+ );
103
115
 
104
116
  this.root.bindToContext();
105
117
  }
@@ -118,6 +130,20 @@ export class TestFluidObject implements ITestFluidObject {
118
130
  */
119
131
  export type ChannelFactoryRegistry = Iterable<[string | undefined, IChannelFactory]>;
120
132
 
133
+ /**
134
+ * Kind of test data object which {@link TestFluidObjectFactory} can create.
135
+ * @internal
136
+ */
137
+ export type TestDataObjectKind = new (
138
+ runtime: IFluidDataStoreRuntime,
139
+ channel: IFluidDataStoreChannel,
140
+ context: IFluidDataStoreContext,
141
+ initialSharedObjectsFactories: ReadonlyMap<string, IChannelFactory<ISharedObject>>,
142
+ ) => IFluidLoadable & {
143
+ request(request: IRequest): Promise<IResponse>;
144
+ initialize(existing: boolean): Promise<void>;
145
+ };
146
+
121
147
  /**
122
148
  * Creates a factory for a TestFluidObject with the given object factory entries. It creates a data store runtime
123
149
  * with the object factories in the entry list. All the entries with an id other than undefined are passed to the
@@ -156,13 +182,14 @@ export class TestFluidObjectFactory implements IFluidDataStoreFactory {
156
182
 
157
183
  /**
158
184
  * Creates a new TestFluidObjectFactory.
159
- * @param factoryEntries - A list of id to IChannelFactory mapping. It creates a data store runtime with each
185
+ * @param initialSharedObjectsFactories - A list of id to IChannelFactory mapping. It creates a data store runtime with each
160
186
  * IChannelFactory. Entries with string ids are passed to the Fluid object so that it can create a shared object
161
187
  * for it.
162
188
  */
163
189
  constructor(
164
- private readonly factoryEntries: ChannelFactoryRegistry,
190
+ private readonly initialSharedObjectsFactories: ChannelFactoryRegistry,
165
191
  public readonly type = "TestFluidObjectFactory",
192
+ private readonly dataObjectKind: TestDataObjectKind = TestFluidObject,
166
193
  ) {}
167
194
 
168
195
  public async instantiateDataStore(
@@ -176,16 +203,17 @@ export class TestFluidObjectFactory implements IFluidDataStoreFactory {
176
203
  dataTypes.set(sharedMapFactory.type, sharedMapFactory);
177
204
 
178
205
  // Add the object factories to the list to be sent to data store runtime.
179
- for (const [, factory] of this.factoryEntries) {
206
+ for (const [, factory] of this.initialSharedObjectsFactories) {
180
207
  dataTypes.set(factory.type, factory);
181
208
  }
182
209
 
183
210
  // Create a map from the factory entries with entries that don't have the id as undefined. This will be
184
211
  // passed to the Fluid object.
185
- const factoryEntriesMapForObject = new Map<string, IChannelFactory>();
186
- for (const [id, factory] of this.factoryEntries) {
212
+ const factoryEntriesMapForObject = new Map<string, IChannelFactory<ISharedObject>>();
213
+ for (const [id, factory] of this.initialSharedObjectsFactories) {
187
214
  if (id !== undefined) {
188
- factoryEntriesMapForObject.set(id, factory);
215
+ // Here we assume the factory produces an ISharedObject.
216
+ factoryEntriesMapForObject.set(id, factory as IChannelFactory<ISharedObject>);
189
217
  }
190
218
  }
191
219
 
@@ -194,19 +222,24 @@ export class TestFluidObjectFactory implements IFluidDataStoreFactory {
194
222
  // The provideEntryPoint callback below always returns TestFluidObject.
195
223
  const dataObject = await rt.entryPoint.get();
196
224
  assert(
197
- dataObject instanceof TestFluidObject,
225
+ dataObject instanceof this.dataObjectKind,
198
226
  "entryPoint should have been initialized by now",
199
227
  );
200
228
  return dataObject.request(request);
201
229
  },
202
230
  );
203
231
 
204
- const runtime = new runtimeClass(context, dataTypes, existing, async () => {
205
- await instance.initialize(true);
206
- return instance;
207
- });
232
+ const runtime: FluidDataStoreRuntime = new runtimeClass(
233
+ context,
234
+ dataTypes,
235
+ existing,
236
+ async () => {
237
+ await instance.initialize(true);
238
+ return instance;
239
+ },
240
+ );
208
241
 
209
- const instance: TestFluidObject = new TestFluidObject(
242
+ const instance = new this.dataObjectKind(
210
243
  runtime, // runtime
211
244
  runtime, // channel
212
245
  context,
@@ -0,0 +1,110 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import {
7
+ IFluidHandle,
8
+ IRequest,
9
+ IResponse,
10
+ type IFluidLoadable,
11
+ } from "@fluidframework/core-interfaces";
12
+ import { fail } from "@fluidframework/core-utils/internal";
13
+ import { FluidObjectHandle } from "@fluidframework/datastore/internal";
14
+ import {
15
+ IChannelFactory,
16
+ IFluidDataStoreRuntime,
17
+ type IChannel,
18
+ } from "@fluidframework/datastore-definitions/internal";
19
+ import {
20
+ IFluidDataStoreChannel,
21
+ IFluidDataStoreContext,
22
+ } from "@fluidframework/runtime-definitions/internal";
23
+ import { create404Response } from "@fluidframework/runtime-utils/internal";
24
+ import type {
25
+ ISharedObject,
26
+ SharedObjectKind,
27
+ } from "@fluidframework/shared-object-base/internal";
28
+
29
+ /**
30
+ * A test Fluid object that will create a shared object for each key-value pair in the factoryEntries passed to load.
31
+ * The shared objects can be retrieved by passing the key of the entry to {@link TestFluidObjectInternal.getInitialSharedObject}.
32
+ * It exposes the IFluidDataStoreContext and IFluidDataStoreRuntime.
33
+ * @remarks
34
+ * This is a simplified (does not use SharedMap) alternative to {@link TestFluidObject} which does not implement the external facing {@link ITestFluidObject} interface.
35
+ * @internal
36
+ */
37
+ export class TestFluidObjectInternal implements IFluidLoadable {
38
+ public get IFluidLoadable() {
39
+ return this;
40
+ }
41
+
42
+ public readonly handle: IFluidHandle<this>;
43
+ private initializationPromise: Promise<void> | undefined;
44
+
45
+ /**
46
+ * Creates a new TestFluidObjectInternal.
47
+ * @param runtime - The data store runtime.
48
+ * @param context - The data store context.
49
+ * @param factoryEntries - A list of id to IChannelFactory mapping. For each item in the list,
50
+ * a shared object is created which can be retrieved by calling {@link TestFluidObjectInternal.getInitialSharedObject} with the id;
51
+ * @param initialSharedObjectsFactories - A collection of ids (which can be passed to {@link TestFluidObjectInternal.getInitialSharedObject})
52
+ * and the corresponding factories to use to create the shared objects during initialization.
53
+ */
54
+ constructor(
55
+ public readonly runtime: IFluidDataStoreRuntime,
56
+ public readonly channel: IFluidDataStoreChannel,
57
+ public readonly context: IFluidDataStoreContext,
58
+ private readonly initialSharedObjectsFactories: ReadonlyMap<
59
+ string,
60
+ IChannelFactory<ISharedObject>
61
+ >,
62
+ ) {
63
+ this.handle = new FluidObjectHandle(this, "", runtime.objectsRoutingContext);
64
+ }
65
+
66
+ /**
67
+ * Retrieves the shared object with the given id:
68
+ * this id must have been a key included in the initialSharedObjectsFactories map passed to the constructor.
69
+ * @param id - The id of the shared object to retrieve.
70
+ */
71
+ public async getInitialSharedObject(id: string): Promise<IChannel> {
72
+ return (await this.runtime.getChannel(id)) ?? fail("Shared object not found");
73
+ }
74
+
75
+ /**
76
+ * Retrieves a shared object with the given id.
77
+ * @param kind - The kind of object to retrieve.
78
+ * @param id - The id of the shared object to retrieve.
79
+ */
80
+ public async getInitialSharedObjectTyped<T>(
81
+ kind: SharedObjectKind<T>,
82
+ id: string,
83
+ ): Promise<IChannel & T> {
84
+ const result = (await this.runtime.getChannel(id)) ?? fail("Shared object not found");
85
+ if (kind.is(result)) {
86
+ return result;
87
+ }
88
+ return fail("Wrong kind of shared object");
89
+ }
90
+
91
+ public async request(request: IRequest): Promise<IResponse> {
92
+ return request.url === "" || request.url === "/" || request.url.startsWith("/?")
93
+ ? { mimeType: "fluid/object", status: 200, value: this }
94
+ : create404Response(request);
95
+ }
96
+
97
+ public async initialize(existing: boolean) {
98
+ const doInitialization = async () => {
99
+ if (!existing) {
100
+ for (const [key, sharedObjectFactory] of this.initialSharedObjectsFactories) {
101
+ const channel = this.runtime.createChannel(key, sharedObjectFactory.type);
102
+ (channel as ISharedObject).bindToContext();
103
+ }
104
+ }
105
+ };
106
+
107
+ this.initializationPromise ??= doInitialization();
108
+ return this.initializationPromise;
109
+ }
110
+ }