@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 +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/retry.d.ts +17 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +40 -0
- package/dist/retry.js.map +1 -0
- package/dist/testObjectProvider.d.ts +25 -2
- package/dist/testObjectProvider.d.ts.map +1 -1
- package/dist/testObjectProvider.js +81 -3
- package/dist/testObjectProvider.js.map +1 -1
- package/package.json +18 -18
- package/src/index.ts +1 -0
- package/src/packageVersion.ts +1 -1
- package/src/retry.ts +50 -0
- package/src/testObjectProvider.ts +90 -6
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";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -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.
|
|
8
|
+
export declare const pkgVersion = "0.58.0-55561";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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"]}
|
package/dist/retry.d.ts
ADDED
|
@@ -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():
|
|
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;
|
|
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.
|
|
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.
|
|
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
|
-
"@fluidframework/container-runtime": "0.
|
|
58
|
-
"@fluidframework/container-runtime-definitions": "0.
|
|
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.
|
|
61
|
-
"@fluidframework/datastore-definitions": "0.
|
|
62
|
-
"@fluidframework/driver-definitions": "^0.
|
|
63
|
-
"@fluidframework/driver-utils": "0.
|
|
64
|
-
"@fluidframework/local-driver": "0.
|
|
65
|
-
"@fluidframework/map": "0.
|
|
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.
|
|
68
|
-
"@fluidframework/routerlicious-driver": "0.
|
|
69
|
-
"@fluidframework/runtime-definitions": "0.
|
|
70
|
-
"@fluidframework/runtime-utils": "0.
|
|
71
|
-
"@fluidframework/telemetry-utils": "0.
|
|
72
|
-
"@fluidframework/test-driver-definitions": "0.
|
|
73
|
-
"@fluidframework/test-runtime-utils": "0.
|
|
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";
|
package/src/packageVersion.ts
CHANGED
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:
|
|
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 =
|
|
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
|
+
}
|