@fluidframework/test-utils 0.57.0-51086 → 0.58.0-55561

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.
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./testObjectProvider";
7
7
  export * from "./loaderContainerTracker";
8
8
  export * from "./localLoader";
9
9
  export * from "./localCodeLoader";
10
+ export * from "./retry";
10
11
  export * from "./testContainerRuntimeFactory";
11
12
  export * from "./testFluidObject";
12
13
  export * from "./timeoutUtils";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ __exportStar(require("./testObjectProvider"), exports);
19
19
  __exportStar(require("./loaderContainerTracker"), exports);
20
20
  __exportStar(require("./localLoader"), exports);
21
21
  __exportStar(require("./localCodeLoader"), exports);
22
+ __exportStar(require("./retry"), exports);
22
23
  __exportStar(require("./testContainerRuntimeFactory"), exports);
23
24
  __exportStar(require("./testFluidObject"), exports);
24
25
  __exportStar(require("./timeoutUtils"), exports);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;AAEH,+CAA6B;AAC7B,uDAAqC;AACrC,2DAAyC;AACzC,gDAA8B;AAC9B,oDAAkC;AAClC,gEAA8C;AAC9C,oDAAkC;AAClC,iDAA+B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport * from \"./interfaces\";\nexport * from \"./testObjectProvider\";\nexport * from \"./loaderContainerTracker\";\nexport * from \"./localLoader\";\nexport * from \"./localCodeLoader\";\nexport * from \"./testContainerRuntimeFactory\";\nexport * from \"./testFluidObject\";\nexport * from \"./timeoutUtils\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;AAEH,+CAA6B;AAC7B,uDAAqC;AACrC,2DAAyC;AACzC,gDAA8B;AAC9B,oDAAkC;AAClC,0CAAwB;AACxB,gEAA8C;AAC9C,oDAAkC;AAClC,iDAA+B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport * from \"./interfaces\";\nexport * from \"./testObjectProvider\";\nexport * from \"./loaderContainerTracker\";\nexport * from \"./localLoader\";\nexport * from \"./localCodeLoader\";\nexport * from \"./retry\";\nexport * from \"./testContainerRuntimeFactory\";\nexport * from \"./testFluidObject\";\nexport * from \"./timeoutUtils\";\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/test-utils";
8
- export declare const pkgVersion = "0.57.0-51086";
8
+ export declare const pkgVersion = "0.58.0-55561";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/test-utils";
11
- exports.pkgVersion = "0.57.0-51086";
11
+ exports.pkgVersion = "0.58.0-55561";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/test-utils\";\nexport const pkgVersion = \"0.57.0-51086\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/test-utils\";\nexport const pkgVersion = \"0.58.0-55561\";\n"]}
@@ -0,0 +1,17 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /**
6
+ * Simple retry mechanism with linear back off to call
7
+ * a function which may eventually return an accepted value.
8
+ *
9
+ * @param callback - the function to execute
10
+ * @param check - the function to check if the value is acceptable
11
+ * @param defaultValue - the default value
12
+ * @param maxTries - maximum number of attempts
13
+ * @param backOffMs - back off between attempts in milliseconds
14
+ * @returns the actual value from the callback when successful or the default value otherwise
15
+ */
16
+ export declare const retryWithEventualValue: <T>(callback: () => Promise<T>, check: (value: T) => boolean, defaultValue: T, maxTries?: number, backOffMs?: number) => Promise<T>;
17
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsBH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,uDAEV,OAAO,uEAWK,CAAC"}
package/dist/retry.js ADDED
@@ -0,0 +1,40 @@
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.retryWithEventualValue = void 0;
8
+ const common_utils_1 = require("@fluidframework/common-utils");
9
+ const retry = async (callback, defaultValue, maxTries, backOffMs) => {
10
+ for (let currentTry = 1; currentTry <= maxTries; currentTry++) {
11
+ try {
12
+ const result = await callback();
13
+ return result;
14
+ }
15
+ catch (error) {
16
+ await common_utils_1.delay(currentTry * backOffMs);
17
+ }
18
+ }
19
+ return Promise.resolve(defaultValue);
20
+ };
21
+ /**
22
+ * Simple retry mechanism with linear back off to call
23
+ * a function which may eventually return an accepted value.
24
+ *
25
+ * @param callback - the function to execute
26
+ * @param check - the function to check if the value is acceptable
27
+ * @param defaultValue - the default value
28
+ * @param maxTries - maximum number of attempts
29
+ * @param backOffMs - back off between attempts in milliseconds
30
+ * @returns the actual value from the callback when successful or the default value otherwise
31
+ */
32
+ const retryWithEventualValue = async (callback, check, defaultValue, maxTries = 20, backOffMs = 50) => retry(async () => {
33
+ const value = await callback();
34
+ if (check(value)) {
35
+ return value;
36
+ }
37
+ throw Error("Not ready");
38
+ }, defaultValue, maxTries, backOffMs);
39
+ exports.retryWithEventualValue = retryWithEventualValue;
40
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAqD;AAErD,MAAM,KAAK,GAAG,KAAK,EACf,QAA0B,EAC1B,YAAe,EACf,QAAgB,EAChB,SAAiB,EACP,EAAE;IACZ,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,IAAI,QAAQ,EAAE,UAAU,EAAE,EAAE;QAC3D,IAAI;YACA,MAAM,MAAM,GAAG,MAAM,QAAQ,EAAE,CAAC;YAChC,OAAO,MAAM,CAAC;SACjB;QAAC,OAAO,KAAK,EAAE;YACZ,MAAM,oBAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;SACvC;KACJ;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AACzC,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AACI,MAAM,sBAAsB,GAAG,KAAK,EACvC,QAA0B,EAC1B,KAA4B,EAC5B,YAAe,EACf,QAAQ,GAAG,EAAE,EACb,SAAS,GAAG,EAAE,EACJ,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE;IAC9B,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE;QACd,OAAO,KAAK,CAAC;KAChB;IAED,MAAM,KAAK,CAAC,WAAW,CAAC,CAAC;AAC7B,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAbzB,QAAA,sBAAsB,0BAaG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { delay } from \"@fluidframework/common-utils\";\n\nconst retry = async <T>(\n callback: () => Promise<T>,\n defaultValue: T,\n maxTries: number,\n backOffMs: number,\n): Promise<T> => {\n for (let currentTry = 1; currentTry <= maxTries; currentTry++) {\n try {\n const result = await callback();\n return result;\n } catch (error) {\n await delay(currentTry * backOffMs);\n }\n }\n\n return Promise.resolve(defaultValue);\n}\n\n/**\n * Simple retry mechanism with linear back off to call\n * a function which may eventually return an accepted value.\n *\n * @param callback - the function to execute\n * @param check - the function to check if the value is acceptable\n * @param defaultValue - the default value\n * @param maxTries - maximum number of attempts\n * @param backOffMs - back off between attempts in milliseconds\n * @returns the actual value from the callback when successful or the default value otherwise\n */\nexport const retryWithEventualValue = async <T>(\n callback: () => Promise<T>,\n check: (value: T) => boolean,\n defaultValue: T,\n maxTries = 20,\n backOffMs = 50,\n): Promise<T> => retry(async () => {\n const value = await callback();\n if (check(value)) {\n return value;\n }\n\n throw Error(\"Not ready\");\n}, defaultValue, maxTries, backOffMs);\n"]}
@@ -3,12 +3,13 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { IContainer, IHostLoader } from "@fluidframework/container-definitions";
6
- import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
6
+ import { ITelemetryGenericEvent, ITelemetryBaseLogger, ITelemetryBaseEvent } from "@fluidframework/common-definitions";
7
7
  import { ILoaderProps, Loader } from "@fluidframework/container-loader";
8
8
  import { IContainerRuntimeOptions } from "@fluidframework/container-runtime";
9
9
  import { IFluidCodeDetails, IRequestHeader } from "@fluidframework/core-interfaces";
10
10
  import { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from "@fluidframework/driver-definitions";
11
11
  import { ITestDriver } from "@fluidframework/test-driver-definitions";
12
+ import { TelemetryLogger } from "@fluidframework/telemetry-utils";
12
13
  import { fluidEntryPoint } from "./localCodeLoader";
13
14
  import { ChannelFactoryRegistry } from "./testFluidObject";
14
15
  export interface IOpProcessingController {
@@ -59,6 +60,27 @@ export interface ITestContainerConfig {
59
60
  loaderProps?: Partial<ILoaderProps>;
60
61
  }
61
62
  export declare const createDocumentId: () => string;
63
+ /**
64
+ * This class tracks events. It allows specifying expected events, which will be looked for in order.
65
+ * It also tracks all unexpected errors.
66
+ * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and
67
+ * any expected events that have not occurred.
68
+ */
69
+ export declare class EventAndErrorTrackingLogger extends TelemetryLogger {
70
+ private readonly baseLogger;
71
+ constructor(baseLogger: ITelemetryBaseLogger);
72
+ private readonly expectedEvents;
73
+ private readonly unexpectedErrors;
74
+ registerExpectedEvent(...orderedExpectedEvents: ITelemetryGenericEvent[]): void;
75
+ send(event: ITelemetryBaseEvent): void;
76
+ reportAndClearTrackedEvents(): {
77
+ expectedNotFound: ({
78
+ index: number;
79
+ event: ITelemetryGenericEvent | undefined;
80
+ } | undefined)[];
81
+ unexpectedErrors: ITelemetryBaseEvent[];
82
+ };
83
+ }
62
84
  /**
63
85
  * Shared base class for test object provider. Contain code for loader and container creation and loading
64
86
  */
@@ -78,7 +100,7 @@ export declare class TestObjectProvider implements ITestObjectProvider {
78
100
  * and factory for TestFluidObject
79
101
  */
80
102
  constructor(LoaderConstructor: typeof Loader, driver: ITestDriver, createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint);
81
- get logger(): ITelemetryBaseLogger;
103
+ get logger(): EventAndErrorTrackingLogger;
82
104
  get documentServiceFactory(): IDocumentServiceFactory;
83
105
  get urlResolver(): IUrlResolver;
84
106
  get documentId(): string;
@@ -127,4 +149,5 @@ export declare class TestObjectProvider implements ITestObjectProvider {
127
149
  ensureSynchronized(): Promise<void>;
128
150
  updateDocumentId(resolvedUrl: IResolvedUrl | undefined): void;
129
151
  }
152
+ export declare function getUnexpectedLogErrorException(logger: EventAndErrorTrackingLogger | undefined, prefix?: string): Error | undefined;
130
153
  //# sourceMappingURL=testObjectProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testObjectProvider.d.ts","sourceRoot":"","sources":["../src/testObjectProvider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,EAA0B,MAAM,kCAAkC,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEzG,OAAO,EAAE,WAAW,EAAmB,MAAM,yCAAyC,CAAC;AAIvF,OAAO,EAAE,eAAe,EAAmB,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAO3D,MAAM,WAAW,uBAAuB;IACpC,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,mBAAmB;IAChC,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe,CAAC;IACvF,YAAY,CACR,cAAc,EAAE,QAAQ,CAAC,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,EAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACpC,WAAW,CAAC;IACf,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACvG,aAAa,CACT,UAAU,EAAE,eAAe,EAC3B,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EACnC,aAAa,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;OAGG;IACH,cAAc,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,WAAW,CAAC;IACxE,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnF,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,EAAE,aAAa,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnH;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAAC;IAEtD,MAAM,EAAE,oBAAoB,CAAC;IAC7B,sBAAsB,EAAE,uBAAuB,CAAC;IAChD,WAAW,EAAE,YAAY,CAAC;IAC1B,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,sBAAsB,EAAE,uBAAuB,CAAC;IAEhD,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;IAEd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACvB;AAED,oBAAY,qBAAqB;IAC7B,MAAM,IAAA;IACN,IAAI,IAAA;CACP;AAED,MAAM,WAAW,oBAAoB;IACjC,qDAAqD;IACrD,mBAAmB,CAAC,EAAE,qBAAqB,CAAC;IAE5C,yFAAyF;IACzF,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAElC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAE1C,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,gBAAgB,QAAO,MAAgB,CAAC;AAkCrD;;GAEG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;aAetC,iBAAiB,EAAE,OAAO,MAAM;aAChC,MAAM,EAAE,WAAW;aACnB,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe;IAhB1G,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAgC;IACxE,OAAO,CAAC,uBAAuB,CAAsC;IACrE,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAE1D,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;;;OAIG;gBAEiB,iBAAiB,EAAE,OAAO,MAAM,EAChC,MAAM,EAAE,WAAW,EACnB,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe;IAK1G,IAAI,MAAM,yBAaT;IAED,IAAI,sBAAsB,4BAKzB;IAED,IAAI,WAAW,iBAKd;IAED,IAAI,UAAU,WAEb;IAED,IAAI,kBAAkB,sBAErB;IAED,IAAI,sBAAsB,IAAI,uBAAuB,CAEpD;IAED;;;;;;;OAOG;IACI,YAAY,CACf,cAAc,EAAE,QAAQ,CAAC,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,EAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAmBvC;;;;;;;;OAQG;IACU,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAkBhF,aAAa,CACtB,UAAU,EAAE,eAAe,EAC3B,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EACnC,aAAa,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAKxD;;;;OAIG;IACI,cAAc,CAAC,mBAAmB,CAAC,EAAE,oBAAoB;IAOhE;;;;OAIG;IACU,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;IAkB/F;;;;;OAKG;IACU,iBAAiB,CAC1B,mBAAmB,CAAC,EAAE,oBAAoB,EAC1C,aAAa,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,CAAC;IAUf,KAAK;IASC,kBAAkB;IAI/B,gBAAgB,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS;CAGzD"}
1
+ {"version":3,"file":"testObjectProvider.d.ts","sourceRoot":"","sources":["../src/testObjectProvider.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.TestObjectProvider = exports.createDocumentId = exports.DataObjectFactoryType = void 0;
7
+ exports.getUnexpectedLogErrorException = exports.TestObjectProvider = exports.EventAndErrorTrackingLogger = exports.createDocumentId = exports.DataObjectFactoryType = void 0;
8
8
  const container_loader_1 = require("@fluidframework/container-loader");
9
9
  const driver_utils_1 = require("@fluidframework/driver-utils");
10
10
  const uuid_1 = require("uuid");
@@ -49,6 +49,66 @@ function getDocumentIdStrategy(type) {
49
49
  };
50
50
  }
51
51
  }
52
+ /**
53
+ * This class tracks events. It allows specifying expected events, which will be looked for in order.
54
+ * It also tracks all unexpected errors.
55
+ * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and
56
+ * any expected events that have not occurred.
57
+ */
58
+ class EventAndErrorTrackingLogger extends telemetry_utils_1.TelemetryLogger {
59
+ constructor(baseLogger) {
60
+ super();
61
+ this.baseLogger = baseLogger;
62
+ this.expectedEvents = [];
63
+ this.unexpectedErrors = [];
64
+ }
65
+ registerExpectedEvent(...orderedExpectedEvents) {
66
+ if (this.expectedEvents.length !== 0) {
67
+ // we don't have to error here. just no reason not to. given the events must be
68
+ // ordered it could be tricky to figure out problems around multiple registrations.
69
+ throw new Error("Expected events already registered.\n"
70
+ + "Call reportAndClearTrackedEvents to clear them before registering more");
71
+ }
72
+ this.expectedEvents.push(...orderedExpectedEvents.map((event, index) => ({ index, event })));
73
+ }
74
+ send(event) {
75
+ var _a;
76
+ const ee = (_a = this.expectedEvents[0]) === null || _a === void 0 ? void 0 : _a.event;
77
+ if ((ee === null || ee === void 0 ? void 0 : ee.eventName) === event.eventName) {
78
+ let matches = true;
79
+ for (const key of Object.keys(ee)) {
80
+ if (ee[key] !== event[key]) {
81
+ matches = false;
82
+ break;
83
+ }
84
+ }
85
+ if (matches) {
86
+ // we found an expected event
87
+ // so remove it from the list of expected events
88
+ // and if it is an error, change it to generic
89
+ // this helps keep our telemetry clear of
90
+ // expected errors.
91
+ this.expectedEvents.shift();
92
+ if (event.category === "error") {
93
+ event.category = "generic";
94
+ }
95
+ }
96
+ }
97
+ if (event.category === "error") {
98
+ this.unexpectedErrors.push(event);
99
+ }
100
+ this.baseLogger.send(event);
101
+ }
102
+ reportAndClearTrackedEvents() {
103
+ const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);
104
+ const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);
105
+ return {
106
+ expectedNotFound,
107
+ unexpectedErrors,
108
+ };
109
+ }
110
+ }
111
+ exports.EventAndErrorTrackingLogger = EventAndErrorTrackingLogger;
52
112
  /**
53
113
  * Shared base class for test object provider. Contain code for loader and container creation and loading
54
114
  */
@@ -69,14 +129,14 @@ class TestObjectProvider {
69
129
  }
70
130
  get logger() {
71
131
  if (this._logger === undefined) {
72
- this._logger = telemetry_utils_1.ChildLogger.create(getTestLogger === null || getTestLogger === void 0 ? void 0 : getTestLogger(), undefined, {
132
+ this._logger = new EventAndErrorTrackingLogger(telemetry_utils_1.ChildLogger.create(getTestLogger === null || getTestLogger === void 0 ? void 0 : getTestLogger(), undefined, {
73
133
  all: {
74
134
  driverType: this.driver.type,
75
135
  driverEndpointName: this.driver.endpointName,
76
136
  driverTenantName: this.driver.tenantName,
77
137
  driverUserIndex: this.driver.userIndex,
78
138
  },
79
- });
139
+ }));
80
140
  }
81
141
  return this._logger;
82
142
  }
@@ -190,6 +250,11 @@ class TestObjectProvider {
190
250
  this._documentServiceFactory = undefined;
191
251
  this._urlResolver = undefined;
192
252
  this._documentIdStrategy.reset();
253
+ const logError = getUnexpectedLogErrorException(this._logger);
254
+ if (logError) {
255
+ throw logError;
256
+ }
257
+ ;
193
258
  this._logger = undefined;
194
259
  this._documentCreated = false;
195
260
  }
@@ -201,4 +266,17 @@ class TestObjectProvider {
201
266
  }
202
267
  }
203
268
  exports.TestObjectProvider = TestObjectProvider;
269
+ function getUnexpectedLogErrorException(logger, prefix) {
270
+ if (logger === undefined) {
271
+ return;
272
+ }
273
+ const results = logger.reportAndClearTrackedEvents();
274
+ if (results.unexpectedErrors.length > 0) {
275
+ return new Error(`${prefix !== null && prefix !== void 0 ? prefix : ""}Unexpected Errors in Logs:\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);
276
+ }
277
+ if (results.expectedNotFound.length > 0) {
278
+ return new Error(`${prefix !== null && prefix !== void 0 ? prefix : ""}Expected Events not found:\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);
279
+ }
280
+ }
281
+ exports.getUnexpectedLogErrorException = getUnexpectedLogErrorException;
204
282
  //# sourceMappingURL=testObjectProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testObjectProvider.js","sourceRoot":"","sources":["../src/testObjectProvider.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 { IContainer, IHostLoader } from \"@fluidframework/container-definitions\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ILoaderProps, Loader, waitContainerToCatchUp } from \"@fluidframework/container-loader\";\nimport { IContainerRuntimeOptions } from \"@fluidframework/container-runtime\";\nimport { IFluidCodeDetails, IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ensureFluidResolvedUrl } from \"@fluidframework/driver-utils\";\nimport { ITestDriver, TestDriverTypes } from \"@fluidframework/test-driver-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { ChildLogger, MultiSinkLogger } from \"@fluidframework/telemetry-utils\";\nimport { LoaderContainerTracker } from \"./loaderContainerTracker\";\nimport { fluidEntryPoint, LocalCodeLoader } from \"./localCodeLoader\";\nimport { createAndAttachContainer } from \"./localLoader\";\nimport { ChannelFactoryRegistry } from \"./testFluidObject\";\n\nconst defaultCodeDetails: IFluidCodeDetails = {\n package: \"defaultTestPackage\",\n config: {},\n};\n\nexport interface IOpProcessingController {\n processIncoming(...containers: IContainer[]): Promise<void>;\n processOutgoing(...containers: IContainer[]): Promise<void>;\n pauseProcessing(...containers: IContainer[]): Promise<void>;\n resumeProcessing(...containers: IContainer[]): void;\n}\n\nexport interface ITestObjectProvider {\n createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint;\n createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ): IHostLoader;\n createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>): Promise<IContainer>;\n loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer>;\n\n /**\n * Used to create a test Container. The Loader/ContainerRuntime/DataRuntime might be different versioned.\n * In generateLocalCompatTest(), this Container and its runtime will be arbitrarily-versioned.\n */\n makeTestLoader(testContainerConfig?: ITestContainerConfig): IHostLoader,\n makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer>,\n loadTestContainer(testContainerConfig?: ITestContainerConfig, requestHeader?: IRequestHeader): Promise<IContainer>,\n /**\n *\n * @param url - Resolved container URL\n */\n updateDocumentId(url: IResolvedUrl | undefined): void,\n\n logger: ITelemetryBaseLogger,\n documentServiceFactory: IDocumentServiceFactory,\n urlResolver: IUrlResolver,\n defaultCodeDetails: IFluidCodeDetails,\n opProcessingController: IOpProcessingController,\n\n ensureSynchronized(): Promise<void>;\n reset(): void,\n\n documentId: string,\n driver: ITestDriver;\n}\n\nexport enum DataObjectFactoryType {\n Primed, // default\n Test,\n}\n\nexport interface ITestContainerConfig {\n /** TestFluidDataObject instead of PrimedDataStore */\n fluidDataObjectType?: DataObjectFactoryType,\n\n /** An array of channel name and DDS factory pair to create on container creation time */\n registry?: ChannelFactoryRegistry,\n\n /** Container runtime options for the container instance */\n runtimeOptions?: IContainerRuntimeOptions,\n\n /** Loader options for the loader used to create containers */\n loaderProps?: Partial<ILoaderProps>,\n}\n\nexport const createDocumentId = (): string => uuid();\n\ninterface IDocumentIdStrategy {\n get(): string;\n update(resolvedUrl?: IResolvedUrl): void;\n reset(): void;\n}\n\n/**\n * Document ID is treated differently by test drivers. The key difference is in generating\n * a new container ID and accessing the container in multi-instance test cases.\n */\nfunction getDocumentIdStrategy(type?: TestDriverTypes): IDocumentIdStrategy {\n let documentId = createDocumentId();\n switch (type) {\n case \"odsp\":\n return {\n get: () => documentId,\n update: () => { }, // do not update the document ID in odsp test cases\n reset: () => { documentId = createDocumentId(); },\n };\n default:\n return {\n get: () => documentId,\n update: (resolvedUrl?: IResolvedUrl) => {\n // Extract the document ID from the resolved container's URL and reset the ID property\n ensureFluidResolvedUrl(resolvedUrl);\n documentId = resolvedUrl.id ?? documentId;\n },\n reset: () => { documentId = createDocumentId(); },\n };\n }\n}\n\n/**\n * Shared base class for test object provider. Contain code for loader and container creation and loading\n */\nexport class TestObjectProvider implements ITestObjectProvider {\n private readonly _loaderContainerTracker = new LoaderContainerTracker();\n private _documentServiceFactory: IDocumentServiceFactory | undefined;\n private _urlResolver: IUrlResolver | undefined;\n private _logger: ITelemetryBaseLogger | undefined;\n private readonly _documentIdStrategy: IDocumentIdStrategy;\n // Since documentId doesn't change we can only create/make one container. Call the load functions instead.\n private _documentCreated = false;\n\n /**\n * Manage objects for loading and creating container, including the driver, loader, and OpProcessingController\n * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name\n * and factory for TestFluidObject\n */\n constructor(\n public readonly LoaderConstructor: typeof Loader,\n public readonly driver: ITestDriver,\n public readonly createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint,\n ) {\n this._documentIdStrategy = getDocumentIdStrategy(driver.type);\n }\n\n get logger() {\n if (this._logger === undefined) {\n this._logger = ChildLogger.create(getTestLogger?.(), undefined,\n {\n all: {\n driverType: this.driver.type,\n driverEndpointName: this.driver.endpointName,\n driverTenantName: this.driver.tenantName,\n driverUserIndex: this.driver.userIndex,\n },\n });\n }\n return this._logger;\n }\n\n get documentServiceFactory() {\n if (!this._documentServiceFactory) {\n this._documentServiceFactory = this.driver.createDocumentServiceFactory();\n }\n return this._documentServiceFactory;\n }\n\n get urlResolver() {\n if (!this._urlResolver) {\n this._urlResolver = this.driver.createUrlResolver();\n }\n return this._urlResolver;\n }\n\n get documentId() {\n return this._documentIdStrategy.get();\n }\n\n get defaultCodeDetails() {\n return defaultCodeDetails;\n }\n\n get opProcessingController(): IOpProcessingController {\n return this._loaderContainerTracker;\n }\n\n /**\n * Create a loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ) {\n const multiSinkLogger = new MultiSinkLogger();\n multiSinkLogger.addLogger(this.logger);\n if (loaderProps?.logger !== undefined) {\n multiSinkLogger.addLogger(loaderProps.logger);\n }\n\n const loader = new this.LoaderConstructor({\n ... loaderProps,\n logger: multiSinkLogger,\n codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),\n urlResolver: loaderProps?.urlResolver ?? this.urlResolver,\n documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,\n });\n this._loaderContainerTracker.add(loader);\n return loader;\n }\n\n /**\n * Create a container using a default document id and code details.\n * Container created is automatically added to the OpProcessingController to manage op flow\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public async createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>) {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadContainer\");\n }\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n const container = await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId),\n );\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n public async loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader): Promise<IContainer> {\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n return loader.resolve({ url: await this.driver.createContainerUrl(this.documentId), headers: requestHeader });\n }\n\n /**\n * Make a test loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n * The version of the loader/containerRuntime/dataRuntime may vary based on compat config of the current run\n * @param testContainerConfig - optional configuring the test Container\n */\n public makeTestLoader(testContainerConfig?: ITestContainerConfig) {\n return this.createLoader(\n [[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]],\n testContainerConfig?.loaderProps,\n );\n }\n\n /**\n * Make a container using a default document id and code details\n * Container loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n */\n public async makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer> {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadTestContainer\");\n }\n const loader = this.makeTestLoader(testContainerConfig);\n const container =\n await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId));\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n /**\n * Load a container using a default document id and code details.\n * IContainer loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n * @param requestHeader - optional headers to be supplied to the loader\n */\n public async loadTestContainer(\n testContainerConfig?: ITestContainerConfig,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer> {\n const loader = this.makeTestLoader(testContainerConfig);\n const container = await loader.resolve({\n url: await this.driver.createContainerUrl(this.documentId),\n headers: requestHeader,\n });\n await waitContainerToCatchUp(container);\n return container;\n }\n\n public reset() {\n this._loaderContainerTracker.reset();\n this._documentServiceFactory = undefined;\n this._urlResolver = undefined;\n this._documentIdStrategy.reset();\n this._logger = undefined;\n this._documentCreated = false;\n }\n\n public async ensureSynchronized() {\n return this._loaderContainerTracker.ensureSynchronized();\n }\n\n updateDocumentId(resolvedUrl: IResolvedUrl | undefined) {\n this._documentIdStrategy.update(resolvedUrl);\n }\n}\n"]}
1
+ {"version":3,"file":"testObjectProvider.js","sourceRoot":"","sources":["../src/testObjectProvider.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 { IContainer, IHostLoader } from \"@fluidframework/container-definitions\";\nimport { ITelemetryGenericEvent, ITelemetryBaseLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { ILoaderProps, Loader, waitContainerToCatchUp } from \"@fluidframework/container-loader\";\nimport { IContainerRuntimeOptions } from \"@fluidframework/container-runtime\";\nimport { IFluidCodeDetails, IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ensureFluidResolvedUrl } from \"@fluidframework/driver-utils\";\nimport { ITestDriver, TestDriverTypes } from \"@fluidframework/test-driver-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { ChildLogger, MultiSinkLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { LoaderContainerTracker } from \"./loaderContainerTracker\";\nimport { fluidEntryPoint, LocalCodeLoader } from \"./localCodeLoader\";\nimport { createAndAttachContainer } from \"./localLoader\";\nimport { ChannelFactoryRegistry } from \"./testFluidObject\";\n\nconst defaultCodeDetails: IFluidCodeDetails = {\n package: \"defaultTestPackage\",\n config: {},\n};\n\nexport interface IOpProcessingController {\n processIncoming(...containers: IContainer[]): Promise<void>;\n processOutgoing(...containers: IContainer[]): Promise<void>;\n pauseProcessing(...containers: IContainer[]): Promise<void>;\n resumeProcessing(...containers: IContainer[]): void;\n}\n\nexport interface ITestObjectProvider {\n createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint;\n createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ): IHostLoader;\n createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>): Promise<IContainer>;\n loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer>;\n\n /**\n * Used to create a test Container. The Loader/ContainerRuntime/DataRuntime might be different versioned.\n * In generateLocalCompatTest(), this Container and its runtime will be arbitrarily-versioned.\n */\n makeTestLoader(testContainerConfig?: ITestContainerConfig): IHostLoader,\n makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer>,\n loadTestContainer(testContainerConfig?: ITestContainerConfig, requestHeader?: IRequestHeader): Promise<IContainer>,\n /**\n *\n * @param url - Resolved container URL\n */\n updateDocumentId(url: IResolvedUrl | undefined): void,\n\n logger: ITelemetryBaseLogger,\n documentServiceFactory: IDocumentServiceFactory,\n urlResolver: IUrlResolver,\n defaultCodeDetails: IFluidCodeDetails,\n opProcessingController: IOpProcessingController,\n\n ensureSynchronized(): Promise<void>;\n reset(): void,\n\n documentId: string,\n driver: ITestDriver;\n}\n\nexport enum DataObjectFactoryType {\n Primed, // default\n Test,\n}\n\nexport interface ITestContainerConfig {\n /** TestFluidDataObject instead of PrimedDataStore */\n fluidDataObjectType?: DataObjectFactoryType,\n\n /** An array of channel name and DDS factory pair to create on container creation time */\n registry?: ChannelFactoryRegistry,\n\n /** Container runtime options for the container instance */\n runtimeOptions?: IContainerRuntimeOptions,\n\n /** Loader options for the loader used to create containers */\n loaderProps?: Partial<ILoaderProps>,\n}\n\nexport const createDocumentId = (): string => uuid();\n\ninterface IDocumentIdStrategy {\n get(): string;\n update(resolvedUrl?: IResolvedUrl): void;\n reset(): void;\n}\n\n/**\n * Document ID is treated differently by test drivers. The key difference is in generating\n * a new container ID and accessing the container in multi-instance test cases.\n */\nfunction getDocumentIdStrategy(type?: TestDriverTypes): IDocumentIdStrategy {\n let documentId = createDocumentId();\n switch (type) {\n case \"odsp\":\n return {\n get: () => documentId,\n update: () => { }, // do not update the document ID in odsp test cases\n reset: () => { documentId = createDocumentId(); },\n };\n default:\n return {\n get: () => documentId,\n update: (resolvedUrl?: IResolvedUrl) => {\n // Extract the document ID from the resolved container's URL and reset the ID property\n ensureFluidResolvedUrl(resolvedUrl);\n documentId = resolvedUrl.id ?? documentId;\n },\n reset: () => { documentId = createDocumentId(); },\n };\n }\n}\n\n/**\n * This class tracks events. It allows specifying expected events, which will be looked for in order.\n * It also tracks all unexpected errors.\n * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and\n * any expected events that have not occurred.\n */\nexport class EventAndErrorTrackingLogger extends TelemetryLogger{\n constructor(private readonly baseLogger: ITelemetryBaseLogger){\n super();\n }\n\n private readonly expectedEvents: ({index:number, event: ITelemetryGenericEvent | undefined} | undefined)[] = []\n private readonly unexpectedErrors: ITelemetryBaseEvent[] =[];\n\n public registerExpectedEvent(... orderedExpectedEvents: ITelemetryGenericEvent[]){\n if(this.expectedEvents.length !== 0){\n // we don't have to error here. just no reason not to. given the events must be\n // ordered it could be tricky to figure out problems around multiple registrations.\n throw new Error(\n \"Expected events already registered.\\n\"\n + \"Call reportAndClearTrackedEvents to clear them before registering more\")\n }\n this.expectedEvents.push(... orderedExpectedEvents.map((event,index)=>({index, event})));\n }\n\n send(event: ITelemetryBaseEvent): void {\n const ee = this.expectedEvents[0]?.event;\n if(ee?.eventName === event.eventName){\n let matches = true;\n for(const key of Object.keys(ee)){\n if(ee[key] !== event[key]){\n matches = false;\n break;\n }\n }\n if(matches){\n // we found an expected event\n // so remove it from the list of expected events\n // and if it is an error, change it to generic\n // this helps keep our telemetry clear of\n // expected errors.\n this.expectedEvents.shift();\n if(event.category === \"error\"){\n event.category = \"generic\";\n }\n }\n }\n if(event.category === \"error\"){\n this.unexpectedErrors.push(event);\n }\n\n this.baseLogger.send(event)\n }\n\n public reportAndClearTrackedEvents(){\n const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);\n const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);\n return {\n expectedNotFound,\n unexpectedErrors,\n }\n }\n}\n\n/**\n * Shared base class for test object provider. Contain code for loader and container creation and loading\n */\nexport class TestObjectProvider implements ITestObjectProvider {\n private readonly _loaderContainerTracker = new LoaderContainerTracker();\n private _documentServiceFactory: IDocumentServiceFactory | undefined;\n private _urlResolver: IUrlResolver | undefined;\n private _logger: EventAndErrorTrackingLogger | undefined;\n private readonly _documentIdStrategy: IDocumentIdStrategy;\n // Since documentId doesn't change we can only create/make one container. Call the load functions instead.\n private _documentCreated = false;\n\n /**\n * Manage objects for loading and creating container, including the driver, loader, and OpProcessingController\n * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name\n * and factory for TestFluidObject\n */\n constructor(\n public readonly LoaderConstructor: typeof Loader,\n public readonly driver: ITestDriver,\n public readonly createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint,\n ) {\n this._documentIdStrategy = getDocumentIdStrategy(driver.type);\n }\n\n get logger(): EventAndErrorTrackingLogger {\n if (this._logger === undefined) {\n this._logger = new EventAndErrorTrackingLogger(\n ChildLogger.create(getTestLogger?.(), undefined,\n {\n all: {\n driverType: this.driver.type,\n driverEndpointName: this.driver.endpointName,\n driverTenantName: this.driver.tenantName,\n driverUserIndex: this.driver.userIndex,\n },\n }));\n }\n return this._logger;\n }\n\n get documentServiceFactory() {\n if (!this._documentServiceFactory) {\n this._documentServiceFactory = this.driver.createDocumentServiceFactory();\n }\n return this._documentServiceFactory;\n }\n\n get urlResolver() {\n if (!this._urlResolver) {\n this._urlResolver = this.driver.createUrlResolver();\n }\n return this._urlResolver;\n }\n\n get documentId() {\n return this._documentIdStrategy.get();\n }\n\n get defaultCodeDetails() {\n return defaultCodeDetails;\n }\n\n get opProcessingController(): IOpProcessingController {\n return this._loaderContainerTracker;\n }\n\n /**\n * Create a loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ) {\n const multiSinkLogger = new MultiSinkLogger();\n multiSinkLogger.addLogger(this.logger);\n if (loaderProps?.logger !== undefined) {\n multiSinkLogger.addLogger(loaderProps.logger);\n }\n\n const loader = new this.LoaderConstructor({\n ... loaderProps,\n logger: multiSinkLogger,\n codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),\n urlResolver: loaderProps?.urlResolver ?? this.urlResolver,\n documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,\n });\n this._loaderContainerTracker.add(loader);\n return loader;\n }\n\n /**\n * Create a container using a default document id and code details.\n * Container created is automatically added to the OpProcessingController to manage op flow\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public async createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>) {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadContainer\");\n }\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n const container = await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId),\n );\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n public async loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader): Promise<IContainer> {\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n return loader.resolve({ url: await this.driver.createContainerUrl(this.documentId), headers: requestHeader });\n }\n\n /**\n * Make a test loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n * The version of the loader/containerRuntime/dataRuntime may vary based on compat config of the current run\n * @param testContainerConfig - optional configuring the test Container\n */\n public makeTestLoader(testContainerConfig?: ITestContainerConfig) {\n return this.createLoader(\n [[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]],\n testContainerConfig?.loaderProps,\n );\n }\n\n /**\n * Make a container using a default document id and code details\n * Container loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n */\n public async makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer> {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadTestContainer\");\n }\n const loader = this.makeTestLoader(testContainerConfig);\n const container =\n await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId));\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n /**\n * Load a container using a default document id and code details.\n * IContainer loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n * @param requestHeader - optional headers to be supplied to the loader\n */\n public async loadTestContainer(\n testContainerConfig?: ITestContainerConfig,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer> {\n const loader = this.makeTestLoader(testContainerConfig);\n const container = await loader.resolve({\n url: await this.driver.createContainerUrl(this.documentId),\n headers: requestHeader,\n });\n await waitContainerToCatchUp(container);\n return container;\n }\n\n public reset() {\n this._loaderContainerTracker.reset();\n this._documentServiceFactory = undefined;\n this._urlResolver = undefined;\n this._documentIdStrategy.reset();\n const logError = getUnexpectedLogErrorException(this._logger);\n if(logError) {\n throw logError\n };\n this._logger = undefined;\n this._documentCreated = false;\n }\n\n public async ensureSynchronized() {\n return this._loaderContainerTracker.ensureSynchronized();\n }\n\n updateDocumentId(resolvedUrl: IResolvedUrl | undefined) {\n this._documentIdStrategy.update(resolvedUrl);\n }\n}\n\nexport function getUnexpectedLogErrorException(logger: EventAndErrorTrackingLogger | undefined, prefix?: string){\n if(logger === undefined){\n return;\n }\n const results = logger.reportAndClearTrackedEvents();\n if(results.unexpectedErrors.length > 0){\n return new Error(\n `${prefix ?? \"\"}Unexpected Errors in Logs:\\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);\n }\n if(results.expectedNotFound.length > 0){\n return new Error(\n `${prefix ?? \"\"}Expected Events not found:\\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);\n }\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/test-utils",
3
- "version": "0.57.0-51086",
3
+ "version": "0.58.0-55561",
4
4
  "description": "Utilities for Fluid tests",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -49,28 +49,28 @@
49
49
  "temp-directory": "nyc/.nyc_output"
50
50
  },
51
51
  "dependencies": {
52
- "@fluidframework/aqueduct": "0.57.0-51086",
52
+ "@fluidframework/aqueduct": "0.58.0-55561",
53
53
  "@fluidframework/common-definitions": "^0.20.1",
54
54
  "@fluidframework/common-utils": "^0.32.1",
55
55
  "@fluidframework/container-definitions": "^0.46.0-0",
56
- "@fluidframework/container-loader": "0.57.0-51086",
57
- "@fluidframework/container-runtime": "0.57.0-51086",
58
- "@fluidframework/container-runtime-definitions": "0.57.0-51086",
56
+ "@fluidframework/container-loader": "0.58.0-55561",
57
+ "@fluidframework/container-runtime": "0.58.0-55561",
58
+ "@fluidframework/container-runtime-definitions": "0.58.0-55561",
59
59
  "@fluidframework/core-interfaces": "^0.42.0",
60
- "@fluidframework/datastore": "0.57.0-51086",
61
- "@fluidframework/datastore-definitions": "0.57.0-51086",
62
- "@fluidframework/driver-definitions": "^0.44.0",
63
- "@fluidframework/driver-utils": "0.57.0-51086",
64
- "@fluidframework/local-driver": "0.57.0-51086",
65
- "@fluidframework/map": "0.57.0-51086",
60
+ "@fluidframework/datastore": "0.58.0-55561",
61
+ "@fluidframework/datastore-definitions": "0.58.0-55561",
62
+ "@fluidframework/driver-definitions": "^0.45.0-0",
63
+ "@fluidframework/driver-utils": "0.58.0-55561",
64
+ "@fluidframework/local-driver": "0.58.0-55561",
65
+ "@fluidframework/map": "0.58.0-55561",
66
66
  "@fluidframework/protocol-definitions": "^0.1026.0",
67
- "@fluidframework/request-handler": "0.57.0-51086",
68
- "@fluidframework/routerlicious-driver": "0.57.0-51086",
69
- "@fluidframework/runtime-definitions": "0.57.0-51086",
70
- "@fluidframework/runtime-utils": "0.57.0-51086",
71
- "@fluidframework/telemetry-utils": "0.57.0-51086",
72
- "@fluidframework/test-driver-definitions": "0.57.0-51086",
73
- "@fluidframework/test-runtime-utils": "0.57.0-51086",
67
+ "@fluidframework/request-handler": "0.58.0-55561",
68
+ "@fluidframework/routerlicious-driver": "0.58.0-55561",
69
+ "@fluidframework/runtime-definitions": "0.58.0-55561",
70
+ "@fluidframework/runtime-utils": "0.58.0-55561",
71
+ "@fluidframework/telemetry-utils": "0.58.0-55561",
72
+ "@fluidframework/test-driver-definitions": "0.58.0-55561",
73
+ "@fluidframework/test-runtime-utils": "0.58.0-55561",
74
74
  "debug": "^4.1.1",
75
75
  "uuid": "^8.3.1"
76
76
  },
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./testObjectProvider";
8
8
  export * from "./loaderContainerTracker";
9
9
  export * from "./localLoader";
10
10
  export * from "./localCodeLoader";
11
+ export * from "./retry";
11
12
  export * from "./testContainerRuntimeFactory";
12
13
  export * from "./testFluidObject";
13
14
  export * from "./timeoutUtils";
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/test-utils";
9
- export const pkgVersion = "0.57.0-51086";
9
+ export const pkgVersion = "0.58.0-55561";
package/src/retry.ts ADDED
@@ -0,0 +1,50 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { delay } from "@fluidframework/common-utils";
7
+
8
+ const retry = async <T>(
9
+ callback: () => Promise<T>,
10
+ defaultValue: T,
11
+ maxTries: number,
12
+ backOffMs: number,
13
+ ): Promise<T> => {
14
+ for (let currentTry = 1; currentTry <= maxTries; currentTry++) {
15
+ try {
16
+ const result = await callback();
17
+ return result;
18
+ } catch (error) {
19
+ await delay(currentTry * backOffMs);
20
+ }
21
+ }
22
+
23
+ return Promise.resolve(defaultValue);
24
+ }
25
+
26
+ /**
27
+ * Simple retry mechanism with linear back off to call
28
+ * a function which may eventually return an accepted value.
29
+ *
30
+ * @param callback - the function to execute
31
+ * @param check - the function to check if the value is acceptable
32
+ * @param defaultValue - the default value
33
+ * @param maxTries - maximum number of attempts
34
+ * @param backOffMs - back off between attempts in milliseconds
35
+ * @returns the actual value from the callback when successful or the default value otherwise
36
+ */
37
+ export const retryWithEventualValue = async <T>(
38
+ callback: () => Promise<T>,
39
+ check: (value: T) => boolean,
40
+ defaultValue: T,
41
+ maxTries = 20,
42
+ backOffMs = 50,
43
+ ): Promise<T> => retry(async () => {
44
+ const value = await callback();
45
+ if (check(value)) {
46
+ return value;
47
+ }
48
+
49
+ throw Error("Not ready");
50
+ }, defaultValue, maxTries, backOffMs);
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { IContainer, IHostLoader } from "@fluidframework/container-definitions";
7
- import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
7
+ import { ITelemetryGenericEvent, ITelemetryBaseLogger, ITelemetryBaseEvent } from "@fluidframework/common-definitions";
8
8
  import { ILoaderProps, Loader, waitContainerToCatchUp } from "@fluidframework/container-loader";
9
9
  import { IContainerRuntimeOptions } from "@fluidframework/container-runtime";
10
10
  import { IFluidCodeDetails, IRequestHeader } from "@fluidframework/core-interfaces";
@@ -12,7 +12,7 @@ import { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from "@fluidframe
12
12
  import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils";
13
13
  import { ITestDriver, TestDriverTypes } from "@fluidframework/test-driver-definitions";
14
14
  import { v4 as uuid } from "uuid";
15
- import { ChildLogger, MultiSinkLogger } from "@fluidframework/telemetry-utils";
15
+ import { ChildLogger, MultiSinkLogger, TelemetryLogger } from "@fluidframework/telemetry-utils";
16
16
  import { LoaderContainerTracker } from "./loaderContainerTracker";
17
17
  import { fluidEntryPoint, LocalCodeLoader } from "./localCodeLoader";
18
18
  import { createAndAttachContainer } from "./localLoader";
@@ -122,6 +122,70 @@ function getDocumentIdStrategy(type?: TestDriverTypes): IDocumentIdStrategy {
122
122
  }
123
123
  }
124
124
 
125
+ /**
126
+ * This class tracks events. It allows specifying expected events, which will be looked for in order.
127
+ * It also tracks all unexpected errors.
128
+ * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and
129
+ * any expected events that have not occurred.
130
+ */
131
+ export class EventAndErrorTrackingLogger extends TelemetryLogger{
132
+ constructor(private readonly baseLogger: ITelemetryBaseLogger){
133
+ super();
134
+ }
135
+
136
+ private readonly expectedEvents: ({index:number, event: ITelemetryGenericEvent | undefined} | undefined)[] = []
137
+ private readonly unexpectedErrors: ITelemetryBaseEvent[] =[];
138
+
139
+ public registerExpectedEvent(... orderedExpectedEvents: ITelemetryGenericEvent[]){
140
+ if(this.expectedEvents.length !== 0){
141
+ // we don't have to error here. just no reason not to. given the events must be
142
+ // ordered it could be tricky to figure out problems around multiple registrations.
143
+ throw new Error(
144
+ "Expected events already registered.\n"
145
+ + "Call reportAndClearTrackedEvents to clear them before registering more")
146
+ }
147
+ this.expectedEvents.push(... orderedExpectedEvents.map((event,index)=>({index, event})));
148
+ }
149
+
150
+ send(event: ITelemetryBaseEvent): void {
151
+ const ee = this.expectedEvents[0]?.event;
152
+ if(ee?.eventName === event.eventName){
153
+ let matches = true;
154
+ for(const key of Object.keys(ee)){
155
+ if(ee[key] !== event[key]){
156
+ matches = false;
157
+ break;
158
+ }
159
+ }
160
+ if(matches){
161
+ // we found an expected event
162
+ // so remove it from the list of expected events
163
+ // and if it is an error, change it to generic
164
+ // this helps keep our telemetry clear of
165
+ // expected errors.
166
+ this.expectedEvents.shift();
167
+ if(event.category === "error"){
168
+ event.category = "generic";
169
+ }
170
+ }
171
+ }
172
+ if(event.category === "error"){
173
+ this.unexpectedErrors.push(event);
174
+ }
175
+
176
+ this.baseLogger.send(event)
177
+ }
178
+
179
+ public reportAndClearTrackedEvents(){
180
+ const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);
181
+ const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);
182
+ return {
183
+ expectedNotFound,
184
+ unexpectedErrors,
185
+ }
186
+ }
187
+ }
188
+
125
189
  /**
126
190
  * Shared base class for test object provider. Contain code for loader and container creation and loading
127
191
  */
@@ -129,7 +193,7 @@ export class TestObjectProvider implements ITestObjectProvider {
129
193
  private readonly _loaderContainerTracker = new LoaderContainerTracker();
130
194
  private _documentServiceFactory: IDocumentServiceFactory | undefined;
131
195
  private _urlResolver: IUrlResolver | undefined;
132
- private _logger: ITelemetryBaseLogger | undefined;
196
+ private _logger: EventAndErrorTrackingLogger | undefined;
133
197
  private readonly _documentIdStrategy: IDocumentIdStrategy;
134
198
  // Since documentId doesn't change we can only create/make one container. Call the load functions instead.
135
199
  private _documentCreated = false;
@@ -147,9 +211,10 @@ export class TestObjectProvider implements ITestObjectProvider {
147
211
  this._documentIdStrategy = getDocumentIdStrategy(driver.type);
148
212
  }
149
213
 
150
- get logger() {
214
+ get logger(): EventAndErrorTrackingLogger {
151
215
  if (this._logger === undefined) {
152
- this._logger = ChildLogger.create(getTestLogger?.(), undefined,
216
+ this._logger = new EventAndErrorTrackingLogger(
217
+ ChildLogger.create(getTestLogger?.(), undefined,
153
218
  {
154
219
  all: {
155
220
  driverType: this.driver.type,
@@ -157,7 +222,7 @@ export class TestObjectProvider implements ITestObjectProvider {
157
222
  driverTenantName: this.driver.tenantName,
158
223
  driverUserIndex: this.driver.userIndex,
159
224
  },
160
- });
225
+ }));
161
226
  }
162
227
  return this._logger;
163
228
  }
@@ -311,6 +376,10 @@ export class TestObjectProvider implements ITestObjectProvider {
311
376
  this._documentServiceFactory = undefined;
312
377
  this._urlResolver = undefined;
313
378
  this._documentIdStrategy.reset();
379
+ const logError = getUnexpectedLogErrorException(this._logger);
380
+ if(logError) {
381
+ throw logError
382
+ };
314
383
  this._logger = undefined;
315
384
  this._documentCreated = false;
316
385
  }
@@ -323,3 +392,18 @@ export class TestObjectProvider implements ITestObjectProvider {
323
392
  this._documentIdStrategy.update(resolvedUrl);
324
393
  }
325
394
  }
395
+
396
+ export function getUnexpectedLogErrorException(logger: EventAndErrorTrackingLogger | undefined, prefix?: string){
397
+ if(logger === undefined){
398
+ return;
399
+ }
400
+ const results = logger.reportAndClearTrackedEvents();
401
+ if(results.unexpectedErrors.length > 0){
402
+ return new Error(
403
+ `${prefix ?? ""}Unexpected Errors in Logs:\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);
404
+ }
405
+ if(results.expectedNotFound.length > 0){
406
+ return new Error(
407
+ `${prefix ?? ""}Expected Events not found:\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);
408
+ }
409
+ }