Skip to content

Commit b7a5234

Browse files
authored
Merge pull request #202 from Dexterp37/ping_testing_api
Bug 1701889 - Implement the ping testing api
2 parents f0d6bd6 + 31051c4 commit b7a5234

File tree

4 files changed

+411
-113
lines changed

4 files changed

+411
-113
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.10.2...main)
44

5+
* [#202](https://github.com/mozilla/glean.js/pull/202): Add a testing API for the ping type.
6+
57
# v0.10.2 (2021-04-26)
68

79
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.10.1...v0.10.2)

glean/src/core/pings/ping_type.ts

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import collectAndStorePing from "../pings/maker.js";
88
import type CommonPingData from "./common_ping_data.js";
99
import { Context } from "../context.js";
1010

11+
type ValidatorFunction = (reason?: string) => Promise<void>;
12+
type PromiseCallback = (value: void | PromiseLike<void>) => void;
13+
1114
/**
1215
* Stores information about a ping.
1316
*
@@ -20,6 +23,12 @@ class PingType implements CommonPingData {
2023
readonly sendIfEmpty: boolean;
2124
readonly reasonCodes: string[];
2225

26+
// The functions and promises required for the test API to
27+
// execute and synchronize with the submission API.
28+
private resolveTestPromiseFunction?: PromiseCallback;
29+
private rejectTestPromiseFunction?: PromiseCallback;
30+
private testCallback?: ValidatorFunction;
31+
2332
constructor (meta: CommonPingData) {
2433
this.name = meta.name;
2534
this.includeClientId = meta.includeClientId;
@@ -44,26 +53,84 @@ class PingType implements CommonPingData {
4453
* `ping_info.reason` part of the payload.
4554
*/
4655
submit(reason?: string): void {
56+
// **** Read this before changing the following code! ****
57+
//
58+
// The Dispatcher does not allow dispatched tasks to await on
59+
// other dispatched tasks. Unfortunately, this causes a deadlock.
60+
// In order to work around that problem, we kick off validation
61+
// right before the actual submission takes place, through another
62+
// async function (and not through the dispatcher). After validation
63+
// is complete, regardless of the outcome, the ping submission is
64+
// finally triggered.
65+
if (this.testCallback) {
66+
this.testCallback(reason)
67+
.then(() => {
68+
PingType._private_internalSubmit(this, reason, this.resolveTestPromiseFunction);
69+
})
70+
.catch(e => {
71+
console.error(`There was an error validating "${this.name}" (${reason ?? "no reason"}):`, e);
72+
PingType._private_internalSubmit(this, reason, this.rejectTestPromiseFunction);
73+
});
74+
} else {
75+
PingType._private_internalSubmit(this, reason);
76+
}
77+
}
78+
79+
private static _private_internalSubmit(instance: PingType, reason?: string, testResolver?: PromiseCallback): void {
4780
Context.dispatcher.launch(async () => {
4881
if (!Context.initialized) {
4982
console.info("Glean must be initialized before submitting pings.");
5083
return;
5184
}
5285

53-
if (!Context.uploadEnabled && !this.isDeletionRequest()) {
86+
if (!Context.uploadEnabled && !instance.isDeletionRequest()) {
5487
console.info("Glean disabled: not submitting pings. Glean may still submit the deletion-request ping.");
5588
return;
5689
}
5790

5891
let correctedReason = reason;
59-
if (reason && !this.reasonCodes.includes(reason)) {
92+
if (reason && !instance.reasonCodes.includes(reason)) {
6093
console.error(`Invalid reason code ${reason} from ${this.name}. Ignoring.`);
6194
correctedReason = undefined;
6295
}
6396

6497
const identifier = generateUUIDv4();
65-
await collectAndStorePing(identifier, this, correctedReason);
98+
await collectAndStorePing(identifier, instance, correctedReason);
99+
100+
if (testResolver) {
101+
testResolver();
102+
103+
// Finally clean up!
104+
instance.resolveTestPromiseFunction = undefined;
105+
instance.rejectTestPromiseFunction = undefined;
106+
instance.testCallback = undefined;
107+
}
108+
});
109+
}
110+
111+
/**
112+
* **Test-only API**
113+
*
114+
* Runs a validation function before the ping is collected.
115+
*
116+
* TODO: Only allow this function to be called on test mode (depends on Bug 1682771).
117+
*
118+
* @param callbackFn The asynchronous validation function to run in order to validate
119+
* the ping content.
120+
*
121+
* @returns A `Promise` resolved when the ping is collected and the validation function
122+
* is executed.
123+
*/
124+
async testBeforeNextSubmit(callbackFn: ValidatorFunction): Promise<void> {
125+
if (this.testCallback) {
126+
console.error(`There is an existing test call for ping "${this.name}". Ignoring.`);
66127
return;
128+
}
129+
130+
return new Promise((resolve, reject) => {
131+
this.resolveTestPromiseFunction = resolve;
132+
this.rejectTestPromiseFunction = reject;
133+
this.testCallback = callbackFn;
67134
});
68135
}
69136
}

glean/tests/core/pings/index.spec.ts

Lines changed: 0 additions & 110 deletions
This file was deleted.

0 commit comments

Comments
 (0)