1515 * limitations under the License.
1616 */
1717
18+ import { Unsubscribe } from '../api/reference_impl' ;
19+
20+ import {
21+ setTestingHooksSpi ,
22+ ExistenceFilterMismatchInfo ,
23+ TestingHooksSpi
24+ } from './testing_hooks_spi' ;
25+
1826/**
19- * Manages "testing hooks", hooks into the internals of the SDK to verify
20- * internal state and events during integration tests. Do not use this class
21- * except for testing purposes.
22- *
23- * There are two ways to retrieve the global singleton instance of this class:
24- * 1. The `instance` property, which returns null if the global singleton
25- * instance has not been created. Use this property if the caller should
26- * "do nothing" if there are no testing hooks registered, such as when
27- * delivering an event to notify registered callbacks.
28- * 2. The `getOrCreateInstance()` method, which creates the global singleton
29- * instance if it has not been created. Use this method if the instance is
30- * needed to, for example, register a callback.
27+ * Testing hooks for use by Firestore's integration test suite to reach into the
28+ * SDK internals to validate logic and behavior that is not visible from the
29+ * public API surface.
3130 *
3231 * @internal
3332 */
3433export class TestingHooks {
35- private readonly onExistenceFilterMismatchCallbacks = new Map <
36- Symbol ,
37- ExistenceFilterMismatchCallback
38- > ( ) ;
39-
40- private constructor ( ) { }
41-
42- /**
43- * Returns the singleton instance of this class, or null if it has not been
44- * initialized.
45- */
46- static get instance ( ) : TestingHooks | null {
47- return gTestingHooksSingletonInstance ;
48- }
49-
50- /**
51- * Returns the singleton instance of this class, creating it if is has never
52- * been created before.
53- */
54- static getOrCreateInstance ( ) : TestingHooks {
55- if ( gTestingHooksSingletonInstance === null ) {
56- gTestingHooksSingletonInstance = new TestingHooks ( ) ;
57- }
58- return gTestingHooksSingletonInstance ;
34+ private constructor ( ) {
35+ throw new Error ( 'instances of this class should not be created' ) ;
5936 }
6037
6138 /**
@@ -72,87 +49,58 @@ export class TestingHooks {
7249 * the first invocation of the returned function does anything; all subsequent
7350 * invocations do nothing.
7451 */
75- onExistenceFilterMismatch (
52+ static onExistenceFilterMismatch (
7653 callback : ExistenceFilterMismatchCallback
77- ) : ( ) => void {
78- const key = Symbol ( ) ;
79- this . onExistenceFilterMismatchCallbacks . set ( key , callback ) ;
80- return ( ) => this . onExistenceFilterMismatchCallbacks . delete ( key ) ;
81- }
82-
83- /**
84- * Invokes all currently-registered `onExistenceFilterMismatch` callbacks.
85- * @param info Information about the existence filter mismatch.
86- */
87- notifyOnExistenceFilterMismatch ( info : ExistenceFilterMismatchInfo ) : void {
88- this . onExistenceFilterMismatchCallbacks . forEach ( callback => callback ( info ) ) ;
54+ ) : Unsubscribe {
55+ return TestingHooksSpiImpl . instance . onExistenceFilterMismatch ( callback ) ;
8956 }
9057}
9158
9259/**
93- * Information about an existence filter mismatch, as specified to callbacks
94- * registered with `TestingUtils.onExistenceFilterMismatch()`.
60+ * The signature of callbacks registered with
61+ * `TestingUtils.onExistenceFilterMismatch()`.
62+ *
63+ * The return value, if any, is ignored.
64+ *
65+ * @internal
9566 */
96- export interface ExistenceFilterMismatchInfo {
97- /** The number of documents that matched the query in the local cache. */
98- localCacheCount : number ;
99-
100- /**
101- * The number of documents that matched the query on the server, as specified
102- * in the ExistenceFilter message's `count` field.
103- */
104- existenceFilterCount : number ;
105-
106- /**
107- * The projectId used when checking documents for membership in the bloom
108- * filter.
109- */
110- projectId : string ;
111-
112- /**
113- * The databaseId used when checking documents for membership in the bloom
114- * filter.
115- */
116- databaseId : string ;
67+ export type ExistenceFilterMismatchCallback = (
68+ info : ExistenceFilterMismatchInfo
69+ ) => unknown ;
11770
118- /**
119- * Information about the bloom filter provided by Watch in the ExistenceFilter
120- * message's `unchangedNames` field. If this property is omitted or undefined
121- * then that means that Watch did _not_ provide a bloom filter.
122- */
123- bloomFilter ?: {
124- /**
125- * Whether a full requery was averted by using the bloom filter. If false,
126- * then something happened, such as a false positive, to prevent using the
127- * bloom filter to avoid a full requery.
128- */
129- applied : boolean ;
71+ /**
72+ * The implementation of `TestingHooksSpi`.
73+ */
74+ class TestingHooksSpiImpl implements TestingHooksSpi {
75+ private readonly existenceFilterMismatchCallbacksById = new Map <
76+ Symbol ,
77+ ExistenceFilterMismatchCallback
78+ > ( ) ;
13079
131- /** The number of hash functions used in the bloom filter. */
132- hashCount : number ;
80+ private constructor ( ) { }
13381
134- /** The number of bytes in the bloom filter's bitmask. */
135- bitmapLength : number ;
82+ static get instance ( ) : TestingHooksSpiImpl {
83+ if ( ! testingHooksSpiImplInstance ) {
84+ testingHooksSpiImplInstance = new TestingHooksSpiImpl ( ) ;
85+ setTestingHooksSpi ( testingHooksSpiImplInstance ) ;
86+ }
87+ return testingHooksSpiImplInstance ;
88+ }
13689
137- /** The number of bits of padding in the last byte of the bloom filter. */
138- padding : number ;
90+ notifyOnExistenceFilterMismatch ( info : ExistenceFilterMismatchInfo ) : void {
91+ this . existenceFilterMismatchCallbacksById . forEach ( callback =>
92+ callback ( info )
93+ ) ;
94+ }
13995
140- /**
141- * Tests the given string for membership in the bloom filter created from
142- * the existence filter; will be undefined if creating the bloom filter
143- * failed.
144- */
145- mightContain ?: ( value : string ) => boolean ;
146- } ;
96+ onExistenceFilterMismatch (
97+ callback : ExistenceFilterMismatchCallback
98+ ) : Unsubscribe {
99+ const id = Symbol ( ) ;
100+ const callbacks = this . existenceFilterMismatchCallbacksById ;
101+ callbacks . set ( id , callback ) ;
102+ return ( ) => callbacks . delete ( id ) ;
103+ }
147104}
148105
149- /**
150- * The signature of callbacks registered with
151- * `TestingUtils.onExistenceFilterMismatch()`.
152- */
153- export type ExistenceFilterMismatchCallback = (
154- info : ExistenceFilterMismatchInfo
155- ) => void ;
156-
157- /** The global singleton instance of `TestingHooks`. */
158- let gTestingHooksSingletonInstance : TestingHooks | null = null ;
106+ let testingHooksSpiImplInstance : TestingHooksSpiImpl | null = null ;
0 commit comments