Skip to content

Commit a4ee260

Browse files
authored
Firestore: Convert testing_hooks_util.h/cc from C++ to Objective-C in FSTTestingHooks.h/mm (#11639)
1 parent 5a7af33 commit a4ee260

File tree

6 files changed

+291
-140
lines changed

6 files changed

+291
-140
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

Firestore/Example/Tests/Integration/API/FIRQueryTests.mm

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
2222
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
2323
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
24-
25-
#include "Firestore/core/test/unit/testutil/testing_hooks_util.h"
24+
#import "Firestore/Example/Tests/Util/FSTTestingHooks.h"
2625

2726
namespace {
2827

@@ -1178,9 +1177,6 @@ - (void)testOrderByEquality {
11781177
}
11791178

11801179
- (void)testResumingAQueryShouldUseBloomFilterToAvoidFullRequery {
1181-
using firebase::firestore::testutil::CaptureExistenceFilterMismatches;
1182-
using firebase::firestore::util::TestingHooks;
1183-
11841180
// TODO(b/291365820): Stop skipping this test when running against the Firestore emulator once
11851181
// the emulator is improved to include a bloom filter in the existence filter messages that it
11861182
// sends.
@@ -1243,11 +1239,11 @@ - (void)testResumingAQueryShouldUseBloomFilterToAvoidFullRequery {
12431239
// Resume the query and save the resulting snapshot for verification.
12441240
// Use some internal testing hooks to "capture" the existence filter mismatches to verify that
12451241
// Watch sent a bloom filter, and it was used to avert a full requery.
1246-
FIRQuerySnapshot *querySnapshot2;
1247-
std::vector<TestingHooks::ExistenceFilterMismatchInfo> existence_filter_mismatches =
1248-
CaptureExistenceFilterMismatches([&] {
1242+
__block FIRQuerySnapshot *querySnapshot2;
1243+
NSArray<FSTTestingHooksExistenceFilterMismatchInfo *> *existenceFilterMismatches =
1244+
[FSTTestingHooks captureExistenceFilterMismatchesDuringBlock:^{
12491245
querySnapshot2 = [self readDocumentSetForRef:collRef source:FIRFirestoreSourceDefault];
1250-
});
1246+
}];
12511247

12521248
// Verify that the snapshot from the resumed query contains the expected documents; that is,
12531249
// that it contains the 50 documents that were _not_ deleted.
@@ -1279,33 +1275,32 @@ - (void)testResumingAQueryShouldUseBloomFilterToAvoidFullRequery {
12791275

12801276
// Verify that Watch sent an existence filter with the correct counts when the query was
12811277
// resumed.
1282-
XCTAssertEqual(existence_filter_mismatches.size(), size_t{1},
1278+
XCTAssertEqual(existenceFilterMismatches.count, 1u,
12831279
@"Watch should have sent exactly 1 existence filter");
1284-
const TestingHooks::ExistenceFilterMismatchInfo &existenceFilterMismatchInfo =
1285-
existence_filter_mismatches[0];
1286-
XCTAssertEqual(existenceFilterMismatchInfo.local_cache_count, 100);
1287-
XCTAssertEqual(existenceFilterMismatchInfo.existence_filter_count, 50);
1280+
FSTTestingHooksExistenceFilterMismatchInfo *existenceFilterMismatchInfo =
1281+
existenceFilterMismatches[0];
1282+
XCTAssertEqual(existenceFilterMismatchInfo.localCacheCount, 100);
1283+
XCTAssertEqual(existenceFilterMismatchInfo.existenceFilterCount, 50);
12881284

12891285
// Verify that Watch sent a valid bloom filter.
1290-
const absl::optional<TestingHooks::BloomFilterInfo> &bloom_filter =
1291-
existence_filter_mismatches[0].bloom_filter;
1292-
XCTAssertTrue(bloom_filter.has_value(),
1293-
"Watch should have included a bloom filter in the existence filter");
1294-
XCTAssertGreaterThan(bloom_filter->hash_count, 0);
1295-
XCTAssertGreaterThan(bloom_filter->bitmap_length, 0);
1296-
XCTAssertGreaterThan(bloom_filter->padding, 0);
1297-
XCTAssertLessThan(bloom_filter->padding, 8);
1286+
FSTTestingHooksBloomFilter *bloomFilter = existenceFilterMismatchInfo.bloomFilter;
1287+
XCTAssertNotNil(bloomFilter,
1288+
"Watch should have included a bloom filter in the existence filter");
1289+
XCTAssertGreaterThan(bloomFilter.hashCount, 0);
1290+
XCTAssertGreaterThan(bloomFilter.bitmapLength, 0);
1291+
XCTAssertGreaterThan(bloomFilter.padding, 0);
1292+
XCTAssertLessThan(bloomFilter.padding, 8);
12981293

12991294
// Verify that the bloom filter was successfully used to avert a full requery. If a false
13001295
// positive occurred then retry the entire test. Although statistically rare, false positives
13011296
// are expected to happen occasionally. When a false positive _does_ happen, just retry the test
13021297
// with a different set of documents. If that retry _also_ experiences a false positive, then
13031298
// fail the test because that is so improbable that something must have gone wrong.
1304-
if (attemptNumber == 1 && !bloom_filter->applied) {
1299+
if (attemptNumber == 1 && !bloomFilter.applied) {
13051300
continue;
13061301
}
13071302

1308-
XCTAssertTrue(bloom_filter->applied,
1303+
XCTAssertTrue(bloomFilter.applied,
13091304
@"The bloom filter should have been successfully applied with attemptNumber=%@",
13101305
@(attemptNumber));
13111306

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// NOTE: For Swift compatibility, please keep this header Objective-C only.
18+
// Swift cannot interact with any C++ definitions.
19+
#import <Foundation/Foundation.h>
20+
21+
@class FIRDocumentReference;
22+
23+
NS_ASSUME_NONNULL_BEGIN
24+
25+
#pragma mark - FSTTestingHooksBloomFilter
26+
27+
/**
28+
* Information about the bloom filter provided by Watch in the ExistenceFilter message's
29+
* `unchanged_names` field.
30+
*/
31+
@interface FSTTestingHooksBloomFilter : NSObject
32+
33+
- (instancetype)init __attribute__((unavailable("instances cannot be created directly")));
34+
35+
/**
36+
* Whether a full requery was averted by using the bloom filter. If false, then something happened,
37+
* such as a false positive, to prevent using the bloom filter to avoid a full requery.
38+
*/
39+
@property(nonatomic, readonly) BOOL applied;
40+
41+
/** The number of hash functions used in the bloom filter. */
42+
@property(nonatomic, readonly) int hashCount;
43+
44+
/** The number of bytes in the bloom filter's bitmask. */
45+
@property(nonatomic, readonly) int bitmapLength;
46+
47+
/** The number of bits of padding in the last byte of the bloom filter. */
48+
@property(nonatomic, readonly) int padding;
49+
50+
@end // @interface FSTTestingHooksBloomFilter
51+
52+
#pragma mark - FSTTestingHooksExistenceFilterMismatchInfo
53+
54+
/**
55+
* Information about an existence filter mismatch.
56+
*/
57+
@interface FSTTestingHooksExistenceFilterMismatchInfo : NSObject
58+
59+
- (instancetype)init __attribute__((unavailable("instances cannot be created directly")));
60+
61+
/** The number of documents that matched the query in the local cache. */
62+
@property(nonatomic, readonly) int localCacheCount;
63+
64+
/**
65+
* The number of documents that matched the query on the server, as specified in the
66+
* `ExistenceFilter` message's `count` field.
67+
*/
68+
@property(nonatomic, readonly) int existenceFilterCount;
69+
70+
/**
71+
* Information about the bloom filter provided by Watch in the ExistenceFilter message's
72+
* `unchanged_names` field. If nil, then that means that Watch did _not_ provide a bloom filter.
73+
*/
74+
@property(nonatomic, readonly, nullable) FSTTestingHooksBloomFilter* bloomFilter;
75+
76+
@end
77+
78+
#pragma mark - FSTTestingHooks
79+
80+
/**
81+
* Manages "testing hooks", hooks into the internals of the SDK to verify internal state and events
82+
* during integration tests.
83+
*/
84+
@interface FSTTestingHooks : NSObject
85+
86+
- (instancetype)init __attribute__((unavailable("instances cannot be created")));
87+
88+
/**
89+
* Captures all existence filter mismatches in the Watch 'Listen' stream that occur during the
90+
* execution of the given block.
91+
*
92+
* @param block The block to execute; during the execution of this block all existence filter
93+
* mismatches will be captured.
94+
*
95+
* @return the captured existence filter mismatches.
96+
*/
97+
+ (NSArray<FSTTestingHooksExistenceFilterMismatchInfo*>*)
98+
captureExistenceFilterMismatchesDuringBlock:(void (^)())block;
99+
100+
@end
101+
102+
NS_ASSUME_NONNULL_END
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "Firestore/Example/Tests/Util/FSTTestingHooks.h"
18+
19+
#import "FIRDocumentReference.h"
20+
21+
#include <memory>
22+
#include <string>
23+
#include <utility>
24+
25+
#include "Firestore/core/src/api/listener_registration.h"
26+
#include "Firestore/core/src/remote/bloom_filter.h"
27+
#include "Firestore/core/src/util/defer.h"
28+
#include "Firestore/core/src/util/string_apple.h"
29+
#include "Firestore/core/src/util/string_format.h"
30+
#include "Firestore/core/src/util/testing_hooks.h"
31+
#include "Firestore/core/test/unit/testutil/async_testing.h"
32+
#include "absl/types/optional.h"
33+
34+
using firebase::firestore::api::ListenerRegistration;
35+
using firebase::firestore::remote::BloomFilter;
36+
using firebase::firestore::testutil::AsyncAccumulator;
37+
using firebase::firestore::util::Defer;
38+
using firebase::firestore::util::MakeStringView;
39+
using firebase::firestore::util::StringFormat;
40+
using firebase::firestore::util::TestingHooks;
41+
42+
#pragma mark - FSTTestingHooksBloomFilter extension
43+
44+
// Add private "init" methods to FSTTestingHooksBloomFilter.
45+
@interface FSTTestingHooksBloomFilter ()
46+
47+
- (instancetype)initWithApplied:(BOOL)applied
48+
hashCount:(int)hashCount
49+
bitmapLength:(int)bitmapLength
50+
padding:(int)padding NS_DESIGNATED_INITIALIZER;
51+
52+
- (instancetype)initWithBloomFilterInfo:(const TestingHooks::BloomFilterInfo&)bloomFilterInfo;
53+
54+
@end
55+
56+
#pragma mark - FSTTestingHooksBloomFilter implementation
57+
58+
@implementation FSTTestingHooksBloomFilter
59+
60+
- (instancetype)initWithApplied:(BOOL)applied
61+
hashCount:(int)hashCount
62+
bitmapLength:(int)bitmapLength
63+
padding:(int)padding {
64+
if (self = [super init]) {
65+
_applied = applied;
66+
_hashCount = hashCount;
67+
_bitmapLength = bitmapLength;
68+
_padding = padding;
69+
}
70+
return self;
71+
}
72+
73+
- (instancetype)initWithBloomFilterInfo:(const TestingHooks::BloomFilterInfo&)bloomFilterInfo {
74+
return [self initWithApplied:bloomFilterInfo.applied
75+
hashCount:bloomFilterInfo.hash_count
76+
bitmapLength:bloomFilterInfo.bitmap_length
77+
padding:bloomFilterInfo.padding];
78+
}
79+
80+
@end
81+
82+
#pragma mark - FSTTestingHooksExistenceFilterMismatchInfo extension
83+
84+
// Add private "init" methods to FSTTestingHooksExistenceFilterMismatchInfo.
85+
@interface FSTTestingHooksExistenceFilterMismatchInfo ()
86+
87+
- (instancetype)initWithLocalCacheCount:(int)localCacheCount
88+
existenceFilterCount:(int)existenceFilterCount
89+
bloomFilter:(nullable FSTTestingHooksBloomFilter*)bloomFilter
90+
NS_DESIGNATED_INITIALIZER;
91+
92+
- (instancetype)initWithExistenceFilterMismatchInfo:
93+
(const TestingHooks::ExistenceFilterMismatchInfo&)existenceFilterMismatchInfo;
94+
95+
@end
96+
97+
#pragma mark - FSTTestingHooksExistenceFilterMismatchInfo implementation
98+
99+
@implementation FSTTestingHooksExistenceFilterMismatchInfo
100+
101+
- (instancetype)initWithLocalCacheCount:(int)localCacheCount
102+
existenceFilterCount:(int)existenceFilterCount
103+
bloomFilter:(nullable FSTTestingHooksBloomFilter*)bloomFilter {
104+
if (self = [super init]) {
105+
_localCacheCount = localCacheCount;
106+
_existenceFilterCount = existenceFilterCount;
107+
_bloomFilter = bloomFilter;
108+
}
109+
return self;
110+
}
111+
112+
- (instancetype)initWithExistenceFilterMismatchInfo:
113+
(const TestingHooks::ExistenceFilterMismatchInfo&)existenceFilterMismatchInfo {
114+
FSTTestingHooksBloomFilter* bloomFilter;
115+
if (existenceFilterMismatchInfo.bloom_filter.has_value()) {
116+
bloomFilter = [[FSTTestingHooksBloomFilter alloc]
117+
initWithBloomFilterInfo:existenceFilterMismatchInfo.bloom_filter.value()];
118+
} else {
119+
bloomFilter = nil;
120+
}
121+
122+
return [self initWithLocalCacheCount:existenceFilterMismatchInfo.local_cache_count
123+
existenceFilterCount:existenceFilterMismatchInfo.existence_filter_count
124+
bloomFilter:bloomFilter];
125+
}
126+
127+
@end
128+
129+
#pragma mark - FSTTestingHooks implementation
130+
131+
@implementation FSTTestingHooks
132+
133+
+ (NSArray<FSTTestingHooksExistenceFilterMismatchInfo*>*)
134+
captureExistenceFilterMismatchesDuringBlock:(void (^)())block {
135+
auto accumulator = AsyncAccumulator<TestingHooks::ExistenceFilterMismatchInfo>::NewInstance();
136+
137+
TestingHooks& testing_hooks = TestingHooks::GetInstance();
138+
std::shared_ptr<ListenerRegistration> registration =
139+
testing_hooks.OnExistenceFilterMismatch(accumulator->AsCallback());
140+
Defer unregister_callback([registration]() { registration->Remove(); });
141+
142+
block();
143+
144+
NSMutableArray<FSTTestingHooksExistenceFilterMismatchInfo*>* mismatches =
145+
[[NSMutableArray alloc] init];
146+
while (!accumulator->IsEmpty()) {
147+
[mismatches addObject:[[FSTTestingHooksExistenceFilterMismatchInfo alloc]
148+
initWithExistenceFilterMismatchInfo:accumulator->Shift()]];
149+
}
150+
151+
return mismatches;
152+
}
153+
154+
@end

Firestore/core/test/unit/testutil/testing_hooks_util.cc

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

0 commit comments

Comments
 (0)