summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@mapbox.com>2019-09-05 18:21:06 -0400
committerJulian Rex <julian.rex@mapbox.com>2019-09-18 16:50:25 -0400
commit30f2de6c2010c4991825f529b519b8669d340e7a (patch)
tree64195e3305dfb2a4fd741fbef3992c50d7b8d30d
parent047fda889b284ce4ab51b8178be0213c2e693274 (diff)
downloadqtlocation-mapboxgl-30f2de6c2010c4991825f529b519b8669d340e7a.tar.gz
[ios] Add tests for #15536
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm150
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj6
-rw-r--r--platform/ios/test/MGLTestAssertionHandler.h17
-rw-r--r--platform/ios/test/MGLTestAssertionHandler.m41
4 files changed, 137 insertions, 77 deletions
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index 398877e452..0138d911bb 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -1,15 +1,16 @@
#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
#import "MGLOfflineStorage_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
-
-#import <XCTest/XCTest.h>
+#import "MGLTestAssertionHandler.h"
#include <mbgl/util/run_loop.hpp>
#pragma clang diagnostic ignored "-Wshadow"
+
@interface MGLOfflineStorageTests : XCTestCase <MGLOfflineStorageDelegate>
@end
@@ -310,7 +311,52 @@
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks - 1, @"Removed pack should have been removed from the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks or -testAddPack.");
}
-- (void)internalAddPacksForBounds:(dispatch_block_t)block {
+- (void)testRemovePackTwiceInSuccession {
+
+ [self addPackIfNeeded];
+
+ NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
+
+ MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs.lastObject;
+ XCTAssertNotNil(pack, @"Added pack should still exist.");
+
+ [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
+ return changeKind == NSKeyValueChangeRemoval && indices.count == 1;
+ }];
+
+ XCTestExpectation *completionHandlerExpectation = [self expectationWithDescription:@"remove pack completion handler"];
+
+ [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:nil];
+
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ [[[NSThread currentThread] threadDictionary] setValue:[[MGLTestAssertionHandler alloc] init] forKey:NSAssertionHandlerKey];
+
+ [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
+ XCTAssertEqual(pack.state, MGLOfflinePackStateInvalid, @"Removed pack should be invalid in the completion handler.");
+ [completionHandlerExpectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:5 handler:nil];
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+
+ XCTAssertEqual(pack.state, MGLOfflinePackStateInvalid, @"Removed pack should have been invalidated synchronously.");
+
+ XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks - 1, @"Removed pack should have been removed from the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks or -testAddPack.");
+}
+
+- (void)addPackIfNeeded {
+ XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"];
+
+ [self addPacks:1 completion:^{
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[expectation] timeout:1.0];
+}
+
+- (void)addPacks:(NSInteger)count completion:(dispatch_block_t)block {
NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8];
MGLCoordinateBounds bounds[] = {
@@ -320,10 +366,15 @@
{{37.7, -122.5}, {37.9, -122.4}} // SF
};
- int count = sizeof(bounds)/sizeof(bounds[0]);
+ int arraySize = sizeof(bounds)/sizeof(bounds[0]);
+
+ count = MIN(count, arraySize);
+ dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < count; i++) {
+
+ dispatch_group_enter(group);
MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:styleURL bounds:bounds[i] fromZoomLevel:20 toZoomLevel:20];
NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{
@"index": @(i)
@@ -335,91 +386,28 @@
XCTAssertNotNil(pack);
XCTAssertNil(error);
- if(block)
- block();
- }];
- }
-}
-
-
-- (void)testRemovePacks1 {
- NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
-
- if (countOfPacks < 4) {
- XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"];
- expectation.expectedFulfillmentCount = 4;
-
- [self internalAddPacksForBounds:^{
- [expectation fulfill];
+ dispatch_group_leave(group);
}];
- [self waitForExpectations:@[expectation] timeout:10.0];
}
- countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
- XCTAssert(countOfPacks > 0);
-
- // Now delete
- XCTestExpectation *expectation = [self expectationWithDescription:@"all packs removed"];
- expectation.expectedFulfillmentCount = countOfPacks;
-
- NSArray *packs = [MGLOfflineStorage sharedOfflineStorage].packs;
- XCTAssertNotNil(packs);
-
- NSArray *validPacks = [packs filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
- MGLOfflinePack *pack = (MGLOfflinePack*)evaluatedObject;
- return pack.state != MGLOfflinePackStateInvalid;
- }]];
-
- for (MGLOfflinePack *pack in validPacks) {
- [[MGLOfflineStorage sharedOfflineStorage] removePack:pack
- withCompletionHandler:^(NSError * _Nullable error) {
- [expectation fulfill];
- }];
+ if (block) {
+ dispatch_group_notify(group, dispatch_get_main_queue(), block);
}
-
- [self waitForExpectations:@[expectation] timeout:60.0];
-
- countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
- XCTAssertEqual(countOfPacks, 0);
-
-
-
- // so on `keyPath` `packs` change (`NSKeyValueChange.settings`)
-// we dispatch to a `SerialQueue` and remove the pack one by one and wait for the first one to be completed before proceeding to reduce the load on the Database access.
-// serialQueue.async { [weak self] in
-// guard let packs = storage.packs else {
-// return []
-// }
-// let validPacks = packs.filter { $0.state != .invalid }
-//
-// for pack in validPacks {
-// let packGroup = DispatchGroup()
-// packGroup.enter()
-// storage.removePack(pack) { [weak self] (error) in
-// packGroup.leave()
-// }
-// // Wait until the pack completion handler is executed
-// // Marking the pack as removed for us
-// packGroup.wait()
-// }
-// }
}
-
-- (void)testRemovePacks {
+// Test to explore https://github.com/mapbox/mapbox-gl-native/issues/15536
+- (void)testRemovePacksOnBackgroundQueueWhileReloading {
NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
if (countOfPacks < 4) {
XCTestExpectation *expectation = [self expectationWithDescription:@"added packs"];
- expectation.expectedFulfillmentCount = 4;
- [self internalAddPacksForBounds:^{
+ [self addPacks:4 completion:^{
[expectation fulfill];
}];
[self waitForExpectations:@[expectation] timeout:10.0];
-
-
}
+
countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
XCTAssert(countOfPacks > 0);
@@ -431,9 +419,14 @@
MGLOfflineStorage *storage = [MGLOfflineStorage sharedOfflineStorage];
- [self internalAddPacksForBounds:nil];
+ [storage reloadPacks];
dispatch_async(queue, ^{
+
+ NSAssertionHandler *oldHandler = [NSAssertionHandler currentHandler];
+ [[[NSThread currentThread] threadDictionary] setValue:[[MGLTestAssertionHandler alloc] init] forKey:NSAssertionHandlerKey];
+
+
NSArray *packs = storage.packs;
if (!packs) {
@@ -448,14 +441,17 @@
for (MGLOfflinePack *pack in validPacks) {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
+// [storage removePack:pack withCompletionHandler:nil];
[storage removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
dispatch_group_leave(group);
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-
-
+
[expectation fulfill];
}
+
+ [[[NSThread currentThread] threadDictionary] setValue:oldHandler forKey:NSAssertionHandlerKey];
+
});
[self waitForExpectations:@[expectation] timeout:60.0];
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 9ac5d564fe..a138e4ef06 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -523,6 +523,7 @@
CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */; };
CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; };
CAA69DA5206DCD0E007279CD /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ CAAA65D92321BBA900F08A39 /* MGLTestAssertionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */; };
CABE5DAD2072FAB40003AF3C /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
CAD9D0AA22A86D6F001B25EE /* MGLResourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */; };
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */; };
@@ -1211,6 +1212,8 @@
CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = "<group>"; };
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = "<group>"; };
CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; };
+ CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTestAssertionHandler.h; sourceTree = "<group>"; };
+ CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTestAssertionHandler.m; sourceTree = "<group>"; };
CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = "<group>"; };
CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "integration-Bridging-Header.h"; sourceTree = "<group>"; };
CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLMapSnapshotterSwiftTests.swift; sourceTree = "<group>"; };
@@ -1758,6 +1761,8 @@
4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */,
A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */,
+ CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */,
+ CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */,
);
name = "Test Helpers";
sourceTree = "<group>";
@@ -3264,6 +3269,7 @@
files = (
A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */,
A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */,
+ CAAA65D92321BBA900F08A39 /* MGLTestAssertionHandler.m in Sources */,
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
diff --git a/platform/ios/test/MGLTestAssertionHandler.h b/platform/ios/test/MGLTestAssertionHandler.h
new file mode 100644
index 0000000000..18ef67a407
--- /dev/null
+++ b/platform/ios/test/MGLTestAssertionHandler.h
@@ -0,0 +1,17 @@
+//
+// MGLTestAssertionHandler.h
+// test
+//
+// Created by Julian Rex on 9/5/19.
+// Copyright © 2019 Mapbox. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLTestAssertionHandler : NSAssertionHandler
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/test/MGLTestAssertionHandler.m b/platform/ios/test/MGLTestAssertionHandler.m
new file mode 100644
index 0000000000..b187a993ba
--- /dev/null
+++ b/platform/ios/test/MGLTestAssertionHandler.m
@@ -0,0 +1,41 @@
+#import "MGLTestAssertionHandler.h"
+
+@implementation MGLTestAssertionHandler
+
+- (void)handleFailureInMethod:(SEL)selector
+ object:(id)object
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ...
+{
+ va_list args;
+ va_start(args, format);
+ NSString *description = [[NSString alloc] initWithFormat:format arguments:args];
+ va_end(args);
+
+ NSLog(@"NSAssert failure: Method `%@` (%@:%lu) for %@: %@",
+ NSStringFromSelector(selector),
+ fileName,
+ line,
+ object,
+ description);
+}
+
+- (void)handleFailureInFunction:(NSString *)functionName
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ...
+{
+ va_list args;
+ va_start(args, format);
+ NSString *description = [[NSString alloc] initWithFormat:format arguments:args];
+ va_end(args);
+
+ NSLog(@"NSCAssert failure: Function `%@` (%@:%lu): %@",
+ functionName,
+ fileName,
+ line,
+ description);
+}
+@end
+