From 152e4d048fa8f9b10b533751a43f0bbb0488450b Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 13:27:39 +0300 Subject: [PATCH 01/62] No concurrency in sender session delegate queue --- AppCenter/AppCenter/Internals/Sender/MSHttpSender.m | 1 + 1 file changed, 1 insertion(+) diff --git a/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m b/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m index b1c34ec349..b8021c7d93 100644 --- a/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m +++ b/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m @@ -351,6 +351,7 @@ - (NSURLSession *)session { NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfiguration.timeoutIntervalForRequest = kRequestTimeout; _session = [NSURLSession sessionWithConfiguration:sessionConfiguration]; + _session.delegateQueue.maxConcurrentOperationCount = 1; } return _session; } From a13a16ea267a5c357567515de26b2c1dcf7a6109 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 15:19:31 +0300 Subject: [PATCH 02/62] Fix mock user defaults --- .../AppCenterTests/Util/MSMockUserDefaults.m | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/AppCenter/AppCenterTests/Util/MSMockUserDefaults.m b/AppCenter/AppCenterTests/Util/MSMockUserDefaults.m index 35186c22b3..ac8a8357c3 100644 --- a/AppCenter/AppCenterTests/Util/MSMockUserDefaults.m +++ b/AppCenter/AppCenterTests/Util/MSMockUserDefaults.m @@ -5,7 +5,8 @@ @interface MSMockUserDefaults () @property(nonatomic) NSMutableDictionary *dictionary; -@property(nonatomic) id mockUserDefaults; +@property(nonatomic) id mockNSUserDefaults; +@property(nonatomic) id mockMSUserDefaults; @end @@ -15,15 +16,15 @@ - (instancetype)init { self = [super init]; if (self) { _dictionary = [NSMutableDictionary new]; - _mockUserDefaults = OCMClassMock([NSUserDefaults class]); - OCMStub([_mockUserDefaults objectForKey:OCMOCK_ANY]).andCall(self, @selector(objectForKey:)); - OCMStub([_mockUserDefaults setObject:OCMOCK_ANY forKey:OCMOCK_ANY]).andCall(self, @selector(setObject:forKey:)); - OCMStub([_mockUserDefaults removeObjectForKey:OCMOCK_ANY]).andCall(self, @selector(removeObjectForKey:)); - OCMStub([_mockUserDefaults standardUserDefaults]).andReturn(self.mockUserDefaults); + _mockNSUserDefaults = OCMClassMock([NSUserDefaults class]); + OCMStub([_mockNSUserDefaults objectForKey:OCMOCK_ANY]).andCall(self, @selector(objectForKey:)); + OCMStub([_mockNSUserDefaults setObject:OCMOCK_ANY forKey:OCMOCK_ANY]).andCall(self, @selector(setObject:forKey:)); + OCMStub([_mockNSUserDefaults removeObjectForKey:OCMOCK_ANY]).andCall(self, @selector(removeObjectForKey:)); + OCMStub([_mockNSUserDefaults standardUserDefaults]).andReturn(self.mockNSUserDefaults); // Mock MSUserDefaults shared method to return this instance. - id userDefaultsMock = OCMClassMock([MSUserDefaults class]); - OCMStub([userDefaultsMock shared]).andReturn(self); + _mockMSUserDefaults = OCMClassMock([MSUserDefaults class]); + OCMStub([_mockMSUserDefaults shared]).andReturn(self); } return self; } @@ -47,7 +48,8 @@ - (void)removeObjectForKey:(NSString *)aKey { - (void)stopMocking { [self.dictionary removeAllObjects]; - [self.mockUserDefaults stopMocking]; + [self.mockNSUserDefaults stopMocking]; + [self.mockMSUserDefaults stopMocking]; } @end From ae2257d70f6b4f85a661eb53df1e6450806f1de0 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 15:20:23 +0300 Subject: [PATCH 03/62] Fix network reachability mocking in distribute test --- .../AppCenterDistributeTests/MSDistributeTests.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 24d19918ce..776f0f23f2 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -1232,6 +1232,9 @@ - (void)testSetupUpdatesWithPreviousFailureOnSamePackageHash { - (void)testSetupUpdatesWithPreviousFailureOnDifferentPackageHash { // If + id reachabilityMock = OCMClassMock([MS_Reachability class]); + OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); + OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); [MSDistributeTestUtil unMockUpdatesAllowedConditions]; id appCenterMock = OCMClassMock([MSAppCenter class]); id distributeMock = OCMPartialMock(self.sut); @@ -1254,7 +1257,7 @@ - (void)testSetupUpdatesWithPreviousFailureOnDifferentPackageHash { XCTAssertNotEqual([self.settingsMock objectForKey:kMSUpdateSetupFailedPackageHashKey], kMSTestReleaseHash); // When - [distributeMock applyEnabledState:YES]; + [self.sut applyEnabledState:YES]; // Then OCMVerify([distributeMock requestInstallInformationWith:kMSTestReleaseHash]); From ed64fd98a6ae615b73892cd071eba07c6e7be897 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 15:52:51 +0300 Subject: [PATCH 04/62] Fix comments formatting --- .../MSDistributeTests.m | 48 +++++-------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 776f0f23f2..407f4b3840 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -643,9 +643,7 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButtonForMandatoryUpdate - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { - /* - * If - */ + // If XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert for private distribution has been displayed"]; @@ -691,9 +689,7 @@ - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { // Persist release to be picked up. [MS_USER_DEFAULTS setObject:[details serializeToDictionary] forKey:kMSMandatoryReleaseKey]; - /* - * When - */ + // When [self.sut checkLatestRelease:@"whateverToken" distributionGroupId:@"whateverGroupId" releaseHash:@"whateverReleaseHash"]; @@ -706,9 +702,7 @@ - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { XCTFail(@"Expectation Failed with error: %@", error); } - /* - * Then - */ + // Then OCMVerify( [self.alertControllerMock alertControllerWithTitle:OCMOCK_ANY message:message]); OCMVerify([self.alertControllerMock @@ -720,14 +714,10 @@ - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { OCMVerifyAll(self.alertControllerMock); }]; - /* - * If - */ + // If expection = [self expectationWithDescription:@"Confirmation alert for public distribution has been displayed"]; - /* - * When - */ + // When [self.sut checkLatestRelease:nil distributionGroupId:@"whateverGroupId" releaseHash:@"whateverReleaseHash"]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; @@ -738,9 +728,7 @@ - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { XCTFail(@"Expectation Failed with error: %@", error); } - /* - * Then - */ + // Then OCMVerify( [self.alertControllerMock alertControllerWithTitle:OCMOCK_ANY message:message]); OCMVerify([self.alertControllerMock @@ -758,9 +746,7 @@ - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { - /* - * If - */ + // If XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert for private distribution has been displayed"]; @@ -777,9 +763,7 @@ - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { [invocation setReturnValue:&test]; }); - /* - * When - */ + // When [self.sut checkLatestRelease:@"whateverToken" distributionGroupId:@"whateverGroupId" releaseHash:@"whateverReleaseHash"]; @@ -787,9 +771,7 @@ - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { [expection fulfill]; }); - /* - * Then - */ + // Then [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { @@ -800,22 +782,16 @@ - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { } }]; - /* - * If - */ + // If expection = [self expectationWithDescription:@"Confirmation alert for public distribution has been displayed"]; - /* - * When - */ + // When [self.sut checkLatestRelease:nil distributionGroupId:@"whateverGroupId" releaseHash:@"whateverReleaseHash"]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); - /* - * Then - */ + // Then [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { From f170d92c3f07b89e280e32999cb747d0c67e26d0 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 18:15:45 +0300 Subject: [PATCH 05/62] Remove unused flag from crashes --- .../AppCenterCrashes/Internals/MSCrashesPrivate.h | 5 ----- AppCenterCrashes/AppCenterCrashes/MSCrashes.mm | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h b/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h index 2466f2437c..51c60886b2 100644 --- a/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h +++ b/AppCenterCrashes/AppCenterCrashes/Internals/MSCrashesPrivate.h @@ -116,11 +116,6 @@ typedef struct MSCrashesCallbacks { */ @property(nonatomic) NSUncaughtExceptionHandler *exceptionHandler; -/** - * A flag that indicates that crashes are currently sent to the backend. - */ -@property(nonatomic) BOOL sendingInProgress; - /** * Temporary storage for crashes logs to handle user confirmation and callbacks. */ diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index 6f773acfa0..295e79b447 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -574,7 +574,7 @@ - (void)configureCrashReporterWithUncaughtExceptionHandlerEnabled:(BOOL)enableUn [self.plCrashReporter setCrashCallbacks:&plCrashCallbacks]; if (![self.plCrashReporter enableCrashReporterAndReturnError:&error]) MSLogError([MSCrashes logTag], @"Could not enable crash reporter: %@", [error localizedDescription]); - NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler(); + NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler(); if (currentHandler && currentHandler != initialHandler) { self.exceptionHandler = currentHandler; MSLogDebug([MSCrashes logTag], @"Exception handler successfully initialized."); @@ -643,7 +643,7 @@ - (void)startCrashProcessing { @"to App Center!"); } } - if (!self.sendingInProgress && self.crashFiles.count > 0) { + if (self.crashFiles.count > 0) { [self processCrashReports]; } } From 11e8ad2147edba1fc87ebef01b129f9907613e37 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 18:16:53 +0300 Subject: [PATCH 06/62] Disable delay processing in crashes tests --- .../AppCenterCrashesTests/MSCrashesTests.mm | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index d82d9d6f8d..54ced6ba7a 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -32,6 +32,7 @@ @interface MSCrashes () + (void)notifyWithUserConfirmation:(MSUserConfirmation)userConfirmation; +- (void)startDelayedCrashProcessing; - (void)startCrashProcessing; - (void)shouldAlwaysSend; - (void)emptyLogBufferFiles; @@ -193,6 +194,10 @@ - (void)testCrashesDelegateWithoutImplementations { - (void)testProcessCrashes { + // If + self.sut = OCMPartialMock(self.sut); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); + // When assertThatBool([MSCrashesTestUtil copyFixtureCrashReportWithFileName:@"live_report_exception"], isTrue()); [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; @@ -209,7 +214,8 @@ - (void)testProcessCrashes { assertThat(self.sut.crashFiles, hasCountOf(0)); // When - self.sut = [MSCrashes new]; + self.sut = OCMPartialMock([MSCrashes new]); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); assertThatBool([MSCrashesTestUtil copyFixtureCrashReportWithFileName:@"live_report_exception"], isTrue()); [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; @@ -217,7 +223,8 @@ - (void)testProcessCrashes { assertThat(self.sut.crashFiles, hasCountOf(1)); // When - self.sut = [MSCrashes new]; + self.sut = OCMPartialMock([MSCrashes new]); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); MSUserConfirmationHandler userConfirmationHandlerYES = ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { return YES; @@ -232,7 +239,8 @@ - (void)testProcessCrashes { assertThat(self.sut.crashFiles, hasCountOf(0)); // When - self.sut = [MSCrashes new]; + self.sut = OCMPartialMock([MSCrashes new]); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); assertThatBool([MSCrashesTestUtil copyFixtureCrashReportWithFileName:@"live_report_exception"], isTrue()); [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; @@ -240,7 +248,8 @@ - (void)testProcessCrashes { assertThat(self.sut.crashFiles, hasCountOf(1)); // When - self.sut = [MSCrashes new]; + self.sut = OCMPartialMock([MSCrashes new]); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); MSUserConfirmationHandler userConfirmationHandlerNO = ^BOOL(__attribute__((unused)) NSArray *_Nonnull errorReports) { return NO; @@ -254,10 +263,14 @@ - (void)testProcessCrashes { - (void)testProcessCrashesWithErrorAttachments { + // If + self.sut = OCMPartialMock(self.sut); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); + // When id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); assertThatBool([MSCrashesTestUtil copyFixtureCrashReportWithFileName:@"live_report_exception"], isTrue()); - [[MSCrashes sharedInstance] startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; + [self.sut startWithLogManager:logManagerMock appSecret:kMSTestAppSecret]; NSString *validString = @"valid"; NSData *validData = [validString dataUsingEncoding:NSUTF8StringEncoding]; NSData *emptyData = [@"" dataUsingEncoding:NSUTF8StringEncoding]; @@ -279,11 +292,11 @@ - (void)testProcessCrashesWithErrorAttachments { id crashesDelegateMock = OCMProtocolMock(@protocol(MSCrashesDelegate)); OCMStub([crashesDelegateMock attachmentsWithCrashes:OCMOCK_ANY forErrorReport:OCMOCK_ANY]).andReturn(logs); OCMStub([crashesDelegateMock crashes:OCMOCK_ANY shouldProcessErrorReport:OCMOCK_ANY]).andReturn(YES); - [[MSCrashes sharedInstance] setDelegate:crashesDelegateMock]; + [self.sut setDelegate:crashesDelegateMock]; // Then OCMExpect([logManagerMock processLog:validLog forGroupId:OCMOCK_ANY]); - [[MSCrashes sharedInstance] startCrashProcessing]; + [self.sut startCrashProcessing]; OCMVerifyAll(logManagerMock); } @@ -582,11 +595,15 @@ - (void)testWarningMessageAboutTooManyErrorAttachments { }]; #pragma clang diagnostic pop + // If + self.sut = OCMPartialMock(self.sut); + OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); + // When assertThatBool([MSCrashesTestUtil copyFixtureCrashReportWithFileName:@"live_report_exception"], isTrue()); - [[MSCrashes sharedInstance] setDelegate:self]; - [[MSCrashes sharedInstance] startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; - [[MSCrashes sharedInstance] startCrashProcessing]; + [self.sut setDelegate:self]; + [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; + [self.sut startCrashProcessing]; XCTAssertTrue(warningMessageHasBeenPrinted); } From 125abbd9c2caae476465c5ff0a6bd8448d4c8190 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 19:03:21 +0300 Subject: [PATCH 07/62] Fix live report crash data loading --- .../MSErrorLogFormatterTests.mm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSErrorLogFormatterTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSErrorLogFormatterTests.mm index 0d549129e6..14e3d28d3a 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSErrorLogFormatterTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSErrorLogFormatterTests.mm @@ -164,12 +164,15 @@ - (void)testProcessIdAndExceptionForObjectiveCExceptionCrash { } - (void)testSelectorForRegisterWithName { - NSData *crashData = [[[MSCrashes sharedInstance] plCrashReporter] generateLiveReport]; + + // If + NSData *crashData = [MSCrashesTestUtil dataOfFixtureCrashReportWithFileName:@"live_report_exception"]; XCTAssertNotNil(crashData); + + // When NSError *error = nil; MSPLCrashReport *report = [[MSPLCrashReport alloc] initWithData:crashData error:&error]; MSPLCrashReportThreadInfo *crashedThread = [MSErrorLogFormatter findCrashedThreadInReport:report]; - MSPLCrashReportRegisterInfo *reg = crashedThread.registers[0]; [MSErrorLogFormatter selectorForRegisterWithName:reg.registerName ofThread:crashedThread report:report]; @@ -178,15 +181,18 @@ - (void)testSelectorForRegisterWithName { } - (void)testAddProcessInfoAndApplicationPath { + + // If NSData *crashData = [MSCrashesTestUtil dataOfFixtureCrashReportWithFileName:@"live_report_exception"]; XCTAssertNotNil(crashData); - + + // When NSError *error = nil; MSPLCrashReport *report = [[MSPLCrashReport alloc] initWithData:crashData error:&error]; - MSAppleErrorLog *actual = [MSAppleErrorLog new]; actual = [MSErrorLogFormatter addProcessInfoAndApplicationPathTo:actual fromCrashReport:report]; + // Then assertThat(actual.processId, equalTo(@(report.processInfo.processID))); XCTAssertEqual(actual.processName, report.processInfo.processName); XCTAssertNotNil(actual.applicationPath); From fd7da74c7befea8d4b21f797712fe2ebd47666db Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 19:30:53 +0300 Subject: [PATCH 08/62] Wait for creation of buffers in the test --- AppCenterCrashes/AppCenterCrashes/MSCrashes.mm | 8 +++++++- AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm index 295e79b447..c1fd985e4d 100644 --- a/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm +++ b/AppCenterCrashes/AppCenterCrashes/MSCrashes.mm @@ -123,6 +123,11 @@ @interface MSCrashes () */ @property(nonatomic) dispatch_queue_t bufferFileQueue; +/** + * A group to wait for creation of buffers in the test. + */ +@property(nonatomic) dispatch_group_t bufferFileGroup; + /** * Semaphore for exclusion with "startDelayedCrashProcessing" method. */ @@ -237,6 +242,7 @@ - (instancetype)init { * as quickly as possible in case the app is crashing fast. */ _bufferFileQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); + _bufferFileGroup = dispatch_group_create(); [self setupLogBuffer]; } return self; @@ -998,7 +1004,7 @@ - (NSURL *)fileURLWithName:(NSString *)name { if (![fileURL checkResourceIsReachableAndReturnError:nil]) { // Create files asynchronously. We don't really care as they are only ever used post-crash. - dispatch_async(self.bufferFileQueue, ^{ + dispatch_group_async(self.bufferFileGroup, self.bufferFileQueue, ^{ [self createBufferFileAtURL:fileURL]; }); return fileURL; diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 54ced6ba7a..31ca54bf39 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -37,6 +37,8 @@ - (void)startCrashProcessing; - (void)shouldAlwaysSend; - (void)emptyLogBufferFiles; +@property(nonatomic) dispatch_group_t bufferFileGroup; + @end @interface MSCrashesTests : XCTestCase @@ -56,6 +58,11 @@ - (void)setUp { - (void)tearDown { [super tearDown]; + + // Wait for creation of buffers. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + + // Delete all files. [self.sut deleteAllFromCrashesDirectory]; [MSCrashesTestUtil deleteAllFilesInDirectory:[[self.sut logBufferDir] path]]; } From 0c78a895e1f25540e25f24156b7d157e273df0a1 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Mon, 13 Nov 2017 20:08:39 +0300 Subject: [PATCH 09/62] Use group wait instead of sleep --- AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 31ca54bf39..614cfaa88f 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -83,8 +83,8 @@ - (void)testNewInstanceWasInitialisedCorrectly { assertThat(self.sut.analyzerInProgressFile, notNilValue()); XCTAssertTrue(msCrashesLogBuffer.size() == ms_crashes_log_buffer_size); - // Creation of buffer files is done asynchronously, we need to give it some time to create the files. - [NSThread sleepForTimeInterval:0.05]; + // Wait for creation of buffers. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:reinterpret_cast([self.sut.logBufferDir path]) @@ -361,8 +361,8 @@ - (void)testDeleteCrashReportsFromDisabledToEnabled { - (void)testSetupLogBufferWorks { // If - // Creation of buffer files is done asynchronously, we need to give it some time to create the files. - [NSThread sleepForTimeInterval:0.05]; + // Wait for creation of buffers. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); // Then NSError *error = [NSError errorWithDomain:@"MSTestingError" code:-57 userInfo:nil]; From 5c4d44ba24cc6e7b040b24b2d978c49648b25ca3 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 15:38:48 +0300 Subject: [PATCH 10/62] Add MSHttpTestUtil to distribute tests --- .../project.pbxproj | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj b/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj index 60416be34c..68ca5730d6 100644 --- a/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj +++ b/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj @@ -88,6 +88,8 @@ B2C070C51E5E6A200076D6A9 /* AppCenterDistributeResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B2C070B81E5E68540076D6A9 /* AppCenterDistributeResources.bundle */; }; BA682AC831677E0806CA2359 /* MSErrorDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = BA6820A043C816916AF34A04 /* MSErrorDetails.h */; }; BA682C81BA750CA5FCB63A51 /* MSErrorDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = BA6826E3C58372A269A6B43A /* MSErrorDetails.m */; }; + F8BEA3CA1FBB0A6E00D4DE37 /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */; }; + F8BEA3CF1FBB0BE400D4DE37 /* MSHttpTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -209,6 +211,9 @@ BA6820A043C816916AF34A04 /* MSErrorDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSErrorDetails.h; sourceTree = ""; }; BA6826E3C58372A269A6B43A /* MSErrorDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSErrorDetails.m; sourceTree = ""; }; F8646E651F349C6D006080AC /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Resources/ru.lproj/AppCenterDistribute.strings; sourceTree = ""; }; + F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OHHTTPStubs.framework; sourceTree = ""; }; + F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MSHttpTestUtil.m; path = ../../../AppCenter/AppCenterTests/Util/MSHttpTestUtil.m; sourceTree = ""; }; + F8BEA3CC1FBB0BDE00D4DE37 /* MSHttpTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MSHttpTestUtil.h; path = ../../../AppCenter/AppCenterTests/Util/MSHttpTestUtil.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -227,6 +232,7 @@ 0471B5E41E4544000022F951 /* libAppCenterDistribute.a in Frameworks */, 38D25E391E7B0AAC00033FC4 /* OCHamcrestIOS.framework in Frameworks */, 0420A69C1ECA7C8E00915619 /* OCMock.framework in Frameworks */, + F8BEA3CA1FBB0A6E00D4DE37 /* OHHTTPStubs.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -354,6 +360,7 @@ B2C070B91E5E68540076D6A9 /* Resources */, 04FD4A1D1E451E12009B4468 /* Products */, 046FDBD51E56830400AF9DD1 /* Vendor */, + F8BEA3C01FBB08BF00D4DE37 /* Frameworks */, ); sourceTree = ""; }; @@ -406,6 +413,7 @@ 04FD4A4A1E453930009B4468 /* libAppCenter.a */, 380304401E7B007E006A55FB /* OCHamcrest */, 380304321E7B007E006A55FB /* OCMock */, + F8BEA3BD1FBB08A900D4DE37 /* OHHTTPStubs */, ); name = Frameworks; sourceTree = ""; @@ -431,6 +439,8 @@ 389638A21E79F557007C3809 /* Util */ = { isa = PBXGroup; children = ( + F8BEA3CC1FBB0BDE00D4DE37 /* MSHttpTestUtil.h */, + F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */, 389638A51E79F60F007C3809 /* MSDistributeTestUtil.h */, 389638A31E79F59D007C3809 /* MSDistributeTestUtil.m */, 04A140C51ECE89B2001CEE94 /* MSMockUserDefaults.h */, @@ -473,6 +483,30 @@ path = AppCenterDistributeResources; sourceTree = ""; }; + F8BEA3BD1FBB08A900D4DE37 /* OHHTTPStubs */ = { + isa = PBXGroup; + children = ( + F8BEA3C71FBB0A5900D4DE37 /* iOS */, + ); + name = OHHTTPStubs; + path = ../../Vendor/iOS/OHHTTPStubs; + sourceTree = ""; + }; + F8BEA3C01FBB08BF00D4DE37 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + F8BEA3C71FBB0A5900D4DE37 /* iOS */ = { + isa = PBXGroup; + children = ( + F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */, + ); + name = iOS; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -691,6 +725,7 @@ 040AF0251E523B80005C1174 /* MSReleaseDetailsTests.m in Sources */, B20DE7B71E5F97330023075C /* MSDistributeUtilTests.m in Sources */, 040AF02A1E52748D005C1174 /* MSDistributeSenderTests.m in Sources */, + F8BEA3CF1FBB0BE400D4DE37 /* MSHttpTestUtil.m in Sources */, 04DC2ECB1E78A3E3003F23B5 /* MSErrorDetailsTests.m in Sources */, 04FD4A341E453531009B4468 /* MSDistributeTests.m in Sources */, 04A140C91ECE89BD001CEE94 /* MSMockUserDefaults.m in Sources */, From f28f496866642ae0d20268248e981112984014ae Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 15:43:34 +0300 Subject: [PATCH 11/62] Add test for removing keys on non recoverable errors --- .../MSDistributeTests.m | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index f90fe4e36b..7161afb12e 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -9,6 +9,7 @@ #import "MSDistributePrivate.h" #import "MSDistributeTestUtil.h" #import "MSDistributeUtil.h" +#import "MSHttpTestUtil.h" #import "MSKeychainUtil.h" #import "MSMockUserDefaults.h" #import "MSServiceAbstractProtected.h" @@ -828,6 +829,46 @@ - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { [reachabilityMock stopMocking]; } +- (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { + + // If + id keychainMock = OCMClassMock([MSKeychainUtil class]); + id reachabilityMock = OCMClassMock([MS_Reachability class]); + OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); + OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); + + // Non recoverable error. + [MSHttpTestUtil stubHttp404Response]; + + // When + [self.sut checkLatestRelease:@"token" + distributionGroupId:@"groupId" + releaseHash:@"releaseHash"]; + + // Then + XCTestExpectation *expection = [self expectationWithDescription:@"checkLatestRelease"]; + dispatch_async(dispatch_get_main_queue(), ^{ + [expection fulfill]; + }); + [self waitForExpectationsWithTimeout:1 + handler:^(NSError *error) { + + // Then + OCMVerify([keychainMock deleteStringForKey:kMSUpdateTokenKey]); + OCMVerify([self.settingsMock removeObjectForKey:kMSSDKHasLaunchedWithDistribute]); + OCMVerify([self.settingsMock removeObjectForKey:kMSUpdateTokenRequestIdKey]); + OCMVerify([self.settingsMock removeObjectForKey:kMSPostponedTimestampKey]); + OCMVerify([self.settingsMock removeObjectForKey:kMSDistributionGroupIdKey]); + if (error) { + XCTFail(@"Expectation Failed with error: %@", error); + } + }]; + + // Clear + [keychainMock stopMocking]; + [reachabilityMock stopMocking]; +} + - (void)testPersistLastestMandatoryUpdate { // If From 3856d13804440d05a5a708f70664de6ce5aa53d1 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 15:56:39 +0300 Subject: [PATCH 12/62] Wait for creation of buffers to avoid corruption on OCMPartialMock --- AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 614cfaa88f..9b1856c622 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -200,6 +200,9 @@ - (void)testCrashesDelegateWithoutImplementations { } - (void)testProcessCrashes { + + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); // If self.sut = OCMPartialMock(self.sut); @@ -269,6 +272,9 @@ - (void)testProcessCrashes { } - (void)testProcessCrashesWithErrorAttachments { + + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); // If self.sut = OCMPartialMock(self.sut); @@ -601,6 +607,9 @@ - (void)testWarningMessageAboutTooManyErrorAttachments { warningMessageHasBeenPrinted = [message isEqualToString:expectedMessage]; }]; #pragma clang diagnostic pop + + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); // If self.sut = OCMPartialMock(self.sut); From 80563ff763243622c87c4644b2f965caf152c805 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 16:24:35 +0300 Subject: [PATCH 13/62] Add test for check latest release on recoverable errors --- .../MSDistributeTests.m | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 7161afb12e..bd535c4b4d 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -859,6 +859,10 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { OCMVerify([self.settingsMock removeObjectForKey:kMSUpdateTokenRequestIdKey]); OCMVerify([self.settingsMock removeObjectForKey:kMSPostponedTimestampKey]); OCMVerify([self.settingsMock removeObjectForKey:kMSDistributionGroupIdKey]); + XCTAssertNil([self.settingsMock objectForKey:kMSSDKHasLaunchedWithDistribute]); + XCTAssertNil([self.settingsMock objectForKey:kMSUpdateTokenRequestIdKey]); + XCTAssertNil([self.settingsMock objectForKey:kMSPostponedTimestampKey]); + XCTAssertNil([self.settingsMock objectForKey:kMSDistributionGroupIdKey]); if (error) { XCTFail(@"Expectation Failed with error: %@", error); } @@ -867,6 +871,53 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { // Clear [keychainMock stopMocking]; [reachabilityMock stopMocking]; + [OHHTTPStubs removeAllStubs]; +} + +- (void)testCheckLatestReleaseOnRecoverableError { + + // If + id keychainMock = OCMClassMock([MSKeychainUtil class]); + id reachabilityMock = OCMClassMock([MS_Reachability class]); + OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); + OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); + + // Recoverable error. + [MSHttpTestUtil stubHttp500Response]; + + // When + OCMReject([keychainMock deleteStringForKey:kMSUpdateTokenKey]); + [self.settingsMock setObject:@1 forKey:kMSSDKHasLaunchedWithDistribute]; + [self.settingsMock setObject:@1 forKey:kMSUpdateTokenRequestIdKey]; + [self.settingsMock setObject:@1 forKey:kMSPostponedTimestampKey]; + [self.settingsMock setObject:@1 forKey:kMSDistributionGroupIdKey]; + [self.sut checkLatestRelease:@"token" + distributionGroupId:@"groupId" + releaseHash:@"releaseHash"]; + + // Then + XCTestExpectation *expection = [self expectationWithDescription:@"checkLatestRelease"]; + dispatch_async(dispatch_get_main_queue(), ^{ + [expection fulfill]; + }); + [self waitForExpectationsWithTimeout:1 + handler:^(NSError *error) { + + // Then + OCMVerifyAll(keychainMock); + XCTAssertNotNil([self.settingsMock objectForKey:kMSSDKHasLaunchedWithDistribute]); + XCTAssertNotNil([self.settingsMock objectForKey:kMSUpdateTokenRequestIdKey]); + XCTAssertNotNil([self.settingsMock objectForKey:kMSPostponedTimestampKey]); + XCTAssertNotNil([self.settingsMock objectForKey:kMSDistributionGroupIdKey]); + if (error) { + XCTFail(@"Expectation Failed with error: %@", error); + } + }]; + + // Clear + [keychainMock stopMocking]; + [reachabilityMock stopMocking]; + [OHHTTPStubs removeAllStubs]; } - (void)testPersistLastestMandatoryUpdate { From f115795c5fb301d43b24e2a27734b279427f69d6 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 16:41:56 +0300 Subject: [PATCH 14/62] Use self.sut instead of new instance in crashes tests --- .../AppCenterCrashesTests/MSCrashesTests.mm | 118 +++++++++++------- 1 file changed, 71 insertions(+), 47 deletions(-) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 9b1856c622..eb61d15749 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -659,22 +659,25 @@ - (void)testTrackModelException { - (void)testSendOrAwaitWhenAlwaysSendIsTrue { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - OCMStub([crashes shouldAlwaysSend]).andReturn(YES); + [self.sut setAutomaticProcessing:NO]; + OCMStub([self.sut shouldAlwaysSend]).andReturn(YES); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { numInvocations++; }) withLogManager:logManagerMock - withCrashes:crashes]; - [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; - NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; + withCrashes:self.sut]; + [self startCrashes:self.sut withReports:YES withLogManager:logManagerMock]; + NSMutableArray *reportIds = [self idListFromReports:[self.sut unprocessedCrashReports]]; // When - BOOL alwaysSendVal = [crashes sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; + BOOL alwaysSendVal = [self.sut sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; // Then XCTAssertEqual([reportIds count], numInvocations); @@ -683,29 +686,32 @@ - (void)testSendOrAwaitWhenAlwaysSendIsTrue { - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyAlwaysSend { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - OCMStub([crashes shouldAlwaysSend]).andReturn(NO); + [self.sut setAutomaticProcessing:NO]; + OCMStub([self.sut shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { numInvocations++; }) withLogManager:logManagerMock - withCrashes:crashes]; - [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; - NSMutableArray *reports = [self idListFromReports:[crashes unprocessedCrashReports]]; + withCrashes:self.sut]; + [self startCrashes:self.sut withReports:YES withLogManager:logManagerMock]; + NSMutableArray *reports = [self idListFromReports:[self.sut unprocessedCrashReports]]; // When - BOOL alwaysSendVal = [crashes sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reports]; + BOOL alwaysSendVal = [self.sut sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reports]; // Then XCTAssertEqual(numInvocations, 0U); XCTAssertFalse(alwaysSendVal); // When - [crashes notifyWithUserConfirmation:MSUserConfirmationAlways]; + [self.sut notifyWithUserConfirmation:MSUserConfirmationAlways]; // Then XCTAssertEqual([reports count], numInvocations); @@ -713,29 +719,32 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyAlwaysSend { - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifySend { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - OCMStub([crashes shouldAlwaysSend]).andReturn(NO); + [self.sut setAutomaticProcessing:NO]; + OCMStub([self.sut shouldAlwaysSend]).andReturn(NO); __block NSUInteger numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { numInvocations++; }) withLogManager:logManagerMock - withCrashes:crashes]; - [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; - NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; + withCrashes:self.sut]; + [self startCrashes:self.sut withReports:YES withLogManager:logManagerMock]; + NSMutableArray *reportIds = [self idListFromReports:[self.sut unprocessedCrashReports]]; // When - BOOL alwaysSendVal = [crashes sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; + BOOL alwaysSendVal = [self.sut sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; // Then XCTAssertEqual(0U, numInvocations); XCTAssertFalse(alwaysSendVal); // When - [crashes notifyWithUserConfirmation:MSUserConfirmationSend]; + [self.sut notifyWithUserConfirmation:MSUserConfirmationSend]; // Then XCTAssertEqual([reportIds count], numInvocations); @@ -743,22 +752,25 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifySend { - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyDontSend { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - OCMStub([crashes shouldAlwaysSend]).andReturn(NO); + [self.sut setAutomaticProcessing:NO]; + OCMStub([self.sut shouldAlwaysSend]).andReturn(NO); __block int numInvocations = 0; [self setProcessLogImplementation:(^(NSInvocation *) { numInvocations++; }) withLogManager:logManagerMock - withCrashes:crashes]; - NSMutableArray *reportIds = [self idListFromReports:[crashes unprocessedCrashReports]]; + withCrashes:self.sut]; + NSMutableArray *reportIds = [self idListFromReports:[self.sut unprocessedCrashReports]]; // When - BOOL alwaysSendVal = [crashes sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; - [crashes notifyWithUserConfirmation:MSUserConfirmationDontSend]; + BOOL alwaysSendVal = [self.sut sendCrashReportsOrAwaitUserConfirmationForFilteredIds:reportIds]; + [self.sut notifyWithUserConfirmation:MSUserConfirmationDontSend]; // Then XCTAssertFalse(alwaysSendVal); @@ -767,14 +779,17 @@ - (void)testSendOrAwaitWhenAlwaysSendIsFalseAndNotifyDontSend { - (void)testGetUnprocessedCrashReportsWhenThereAreNone { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - [self startCrashes:crashes withReports:NO withLogManager:logManagerMock]; + [self.sut setAutomaticProcessing:NO]; + [self startCrashes:self.sut withReports:NO withLogManager:logManagerMock]; // When - NSArray *reports = [crashes unprocessedCrashReports]; + NSArray *reports = [self.sut unprocessedCrashReports]; // Then XCTAssertEqual([reports count], 0U); @@ -782,10 +797,13 @@ - (void)testGetUnprocessedCrashReportsWhenThereAreNone { - (void)testSendErrorAttachments { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; + [self.sut setAutomaticProcessing:NO]; MSErrorReport *report = OCMPartialMock([MSErrorReport new]); OCMStub([report incidentIdentifier]).andReturn(@"incidentId"); __block NSUInteger numInvocations = 0; @@ -798,14 +816,14 @@ - (void)testSendErrorAttachments { [enqueuedAttachments addObject:attachmentLog]; }) withLogManager:logManagerMock - withCrashes:crashes]; - [self startCrashes:crashes withReports:NO withLogManager:logManagerMock]; + withCrashes:self.sut]; + [self startCrashes:self.sut withReports:NO withLogManager:logManagerMock]; // When [attachments addObject:[[MSErrorAttachmentLog alloc] initWithFilename:@"name" attachmentText:@"text1"]]; [attachments addObject:[[MSErrorAttachmentLog alloc] initWithFilename:@"name" attachmentText:@"text2"]]; [attachments addObject:[[MSErrorAttachmentLog alloc] initWithFilename:@"name" attachmentText:@"text3"]]; - [crashes sendErrorAttachments:attachments withIncidentIdentifier:report.incidentIdentifier]; + [self.sut sendErrorAttachments:attachments withIncidentIdentifier:report.incidentIdentifier]; // Then XCTAssertEqual([attachments count], numInvocations); @@ -816,14 +834,17 @@ - (void)testSendErrorAttachments { - (void)testGetUnprocessedCrashReports { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - NSArray *reports = [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; + [self.sut setAutomaticProcessing:NO]; + NSArray *reports = [self startCrashes:self.sut withReports:YES withLogManager:logManagerMock]; // When - NSArray *retrievedReports = [crashes unprocessedCrashReports]; + NSArray *retrievedReports = [self.sut unprocessedCrashReports]; // Then XCTAssertEqual([reports count], [retrievedReports count]); @@ -841,14 +862,17 @@ - (void)testGetUnprocessedCrashReports { - (void)testStartingCrashesWithoutAutomaticProcessing { + // Wait for creation of buffers to avoid corruption on OCMPartialMock. + dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); + // If - MSCrashes *crashes = OCMPartialMock([MSCrashes new]); + self.sut = OCMPartialMock(self.sut); id logManagerMock = OCMProtocolMock(@protocol(MSLogManager)); - [crashes setAutomaticProcessing:NO]; - NSArray *reports = [self startCrashes:crashes withReports:YES withLogManager:logManagerMock]; + [self.sut setAutomaticProcessing:NO]; + NSArray *reports = [self startCrashes:self.sut withReports:YES withLogManager:logManagerMock]; // When - NSArray *retrievedReports = [crashes unprocessedCrashReports]; + NSArray *retrievedReports = [self.sut unprocessedCrashReports]; // Then XCTAssertEqual([reports count], [retrievedReports count]); From 183785029d85c5ef277d0e269c04ffec8fc33e44 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 16:58:01 +0300 Subject: [PATCH 15/62] Check that update is not handled on http errors --- .../AppCenterDistributeTests/MSDistributeTests.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index bd535c4b4d..1ec3f1ab53 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -832,6 +832,8 @@ - (void)testDontShowConfirmationAlertIfNoMandatoryReleaseWhileNoNetwork { - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { // If + id distributeMock = OCMPartialMock(self.sut); + OCMReject([distributeMock handleUpdate:OCMOCK_ANY]); id keychainMock = OCMClassMock([MSKeychainUtil class]); id reachabilityMock = OCMClassMock([MS_Reachability class]); OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); @@ -854,6 +856,7 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { handler:^(NSError *error) { // Then + OCMVerifyAll(distributeMock); OCMVerify([keychainMock deleteStringForKey:kMSUpdateTokenKey]); OCMVerify([self.settingsMock removeObjectForKey:kMSSDKHasLaunchedWithDistribute]); OCMVerify([self.settingsMock removeObjectForKey:kMSUpdateTokenRequestIdKey]); @@ -869,6 +872,7 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { }]; // Clear + [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; [OHHTTPStubs removeAllStubs]; @@ -877,7 +881,10 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { - (void)testCheckLatestReleaseOnRecoverableError { // If + id distributeMock = OCMPartialMock(self.sut); + OCMReject([distributeMock handleUpdate:OCMOCK_ANY]); id keychainMock = OCMClassMock([MSKeychainUtil class]); + OCMReject([keychainMock deleteStringForKey:kMSUpdateTokenKey]); id reachabilityMock = OCMClassMock([MS_Reachability class]); OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); @@ -886,7 +893,6 @@ - (void)testCheckLatestReleaseOnRecoverableError { [MSHttpTestUtil stubHttp500Response]; // When - OCMReject([keychainMock deleteStringForKey:kMSUpdateTokenKey]); [self.settingsMock setObject:@1 forKey:kMSSDKHasLaunchedWithDistribute]; [self.settingsMock setObject:@1 forKey:kMSUpdateTokenRequestIdKey]; [self.settingsMock setObject:@1 forKey:kMSPostponedTimestampKey]; @@ -904,6 +910,7 @@ - (void)testCheckLatestReleaseOnRecoverableError { handler:^(NSError *error) { // Then + OCMVerifyAll(distributeMock); OCMVerifyAll(keychainMock); XCTAssertNotNil([self.settingsMock objectForKey:kMSSDKHasLaunchedWithDistribute]); XCTAssertNotNil([self.settingsMock objectForKey:kMSUpdateTokenRequestIdKey]); @@ -915,6 +922,7 @@ - (void)testCheckLatestReleaseOnRecoverableError { }]; // Clear + [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; [OHHTTPStubs removeAllStubs]; From 11f6ae6ae55f09d17d8341fe226001d8ad66da3d Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 17:11:30 +0300 Subject: [PATCH 16/62] Mock network in distribute tests --- .../AppCenterDistributeTests/MSDistributeTests.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 1ec3f1ab53..6b46258901 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -82,6 +82,9 @@ - (void)setUp { self.sut = [MSDistribute new]; self.settingsMock = [MSMockUserDefaults new]; + // Mock network. + [MSHttpTestUtil stubHttp200Response]; + // Mock NSBundle self.bundleMock = OCMClassMock([NSBundle class]); OCMStub([self.bundleMock mainBundle]).andReturn(self.bundleMock); @@ -113,6 +116,7 @@ - (void)tearDown { [self waitForExpectations:@[ expection ] timeout:1]; // Clear + [OHHTTPStubs removeAllStubs]; [MSKeychainUtil clear]; [self.parserMock stopMocking]; [self.settingsMock stopMocking]; @@ -875,7 +879,6 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; - [OHHTTPStubs removeAllStubs]; } - (void)testCheckLatestReleaseOnRecoverableError { @@ -925,7 +928,6 @@ - (void)testCheckLatestReleaseOnRecoverableError { [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; - [OHHTTPStubs removeAllStubs]; } - (void)testPersistLastestMandatoryUpdate { From fb89aa83eddde8cb2dbbbe85b8ce96a9be6a9853 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 17:14:03 +0300 Subject: [PATCH 17/62] Mock network in distribute tests --- .../project.pbxproj | 35 +++++++++++++++++++ .../MSDistributeTests.m | 5 +++ 2 files changed, 40 insertions(+) diff --git a/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj b/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj index 60416be34c..68ca5730d6 100644 --- a/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj +++ b/AppCenterDistribute/AppCenterDistribute.xcodeproj/project.pbxproj @@ -88,6 +88,8 @@ B2C070C51E5E6A200076D6A9 /* AppCenterDistributeResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B2C070B81E5E68540076D6A9 /* AppCenterDistributeResources.bundle */; }; BA682AC831677E0806CA2359 /* MSErrorDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = BA6820A043C816916AF34A04 /* MSErrorDetails.h */; }; BA682C81BA750CA5FCB63A51 /* MSErrorDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = BA6826E3C58372A269A6B43A /* MSErrorDetails.m */; }; + F8BEA3CA1FBB0A6E00D4DE37 /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */; }; + F8BEA3CF1FBB0BE400D4DE37 /* MSHttpTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -209,6 +211,9 @@ BA6820A043C816916AF34A04 /* MSErrorDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSErrorDetails.h; sourceTree = ""; }; BA6826E3C58372A269A6B43A /* MSErrorDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSErrorDetails.m; sourceTree = ""; }; F8646E651F349C6D006080AC /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Resources/ru.lproj/AppCenterDistribute.strings; sourceTree = ""; }; + F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OHHTTPStubs.framework; sourceTree = ""; }; + F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MSHttpTestUtil.m; path = ../../../AppCenter/AppCenterTests/Util/MSHttpTestUtil.m; sourceTree = ""; }; + F8BEA3CC1FBB0BDE00D4DE37 /* MSHttpTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MSHttpTestUtil.h; path = ../../../AppCenter/AppCenterTests/Util/MSHttpTestUtil.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -227,6 +232,7 @@ 0471B5E41E4544000022F951 /* libAppCenterDistribute.a in Frameworks */, 38D25E391E7B0AAC00033FC4 /* OCHamcrestIOS.framework in Frameworks */, 0420A69C1ECA7C8E00915619 /* OCMock.framework in Frameworks */, + F8BEA3CA1FBB0A6E00D4DE37 /* OHHTTPStubs.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -354,6 +360,7 @@ B2C070B91E5E68540076D6A9 /* Resources */, 04FD4A1D1E451E12009B4468 /* Products */, 046FDBD51E56830400AF9DD1 /* Vendor */, + F8BEA3C01FBB08BF00D4DE37 /* Frameworks */, ); sourceTree = ""; }; @@ -406,6 +413,7 @@ 04FD4A4A1E453930009B4468 /* libAppCenter.a */, 380304401E7B007E006A55FB /* OCHamcrest */, 380304321E7B007E006A55FB /* OCMock */, + F8BEA3BD1FBB08A900D4DE37 /* OHHTTPStubs */, ); name = Frameworks; sourceTree = ""; @@ -431,6 +439,8 @@ 389638A21E79F557007C3809 /* Util */ = { isa = PBXGroup; children = ( + F8BEA3CC1FBB0BDE00D4DE37 /* MSHttpTestUtil.h */, + F8BEA3CB1FBB0BDE00D4DE37 /* MSHttpTestUtil.m */, 389638A51E79F60F007C3809 /* MSDistributeTestUtil.h */, 389638A31E79F59D007C3809 /* MSDistributeTestUtil.m */, 04A140C51ECE89B2001CEE94 /* MSMockUserDefaults.h */, @@ -473,6 +483,30 @@ path = AppCenterDistributeResources; sourceTree = ""; }; + F8BEA3BD1FBB08A900D4DE37 /* OHHTTPStubs */ = { + isa = PBXGroup; + children = ( + F8BEA3C71FBB0A5900D4DE37 /* iOS */, + ); + name = OHHTTPStubs; + path = ../../Vendor/iOS/OHHTTPStubs; + sourceTree = ""; + }; + F8BEA3C01FBB08BF00D4DE37 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + F8BEA3C71FBB0A5900D4DE37 /* iOS */ = { + isa = PBXGroup; + children = ( + F8BEA3C81FBB0A5900D4DE37 /* OHHTTPStubs.framework */, + ); + name = iOS; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -691,6 +725,7 @@ 040AF0251E523B80005C1174 /* MSReleaseDetailsTests.m in Sources */, B20DE7B71E5F97330023075C /* MSDistributeUtilTests.m in Sources */, 040AF02A1E52748D005C1174 /* MSDistributeSenderTests.m in Sources */, + F8BEA3CF1FBB0BE400D4DE37 /* MSHttpTestUtil.m in Sources */, 04DC2ECB1E78A3E3003F23B5 /* MSErrorDetailsTests.m in Sources */, 04FD4A341E453531009B4468 /* MSDistributeTests.m in Sources */, 04A140C91ECE89BD001CEE94 /* MSMockUserDefaults.m in Sources */, diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 32682bd6f6..96448ba4f2 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -9,6 +9,7 @@ #import "MSDistributePrivate.h" #import "MSDistributeTestUtil.h" #import "MSDistributeUtil.h" +#import "MSHttpTestUtil.h" #import "MSKeychainUtil.h" #import "MSMockUserDefaults.h" #import "MSServiceAbstractProtected.h" @@ -81,6 +82,9 @@ - (void)setUp { self.sut = [MSDistribute new]; self.settingsMock = [MSMockUserDefaults new]; + // Mock network. + [MSHttpTestUtil stubHttp200Response]; + // Mock NSBundle self.bundleMock = OCMClassMock([NSBundle class]); OCMStub([self.bundleMock mainBundle]).andReturn(self.bundleMock); @@ -112,6 +116,7 @@ - (void)tearDown { [self waitForExpectations:@[ expection ] timeout:1]; // Clear + [OHHTTPStubs removeAllStubs]; [MSKeychainUtil clear]; [self.parserMock stopMocking]; [self.settingsMock stopMocking]; From dc2dd68ad00bc371c56eb2657b18d83aa3613306 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Tue, 14 Nov 2017 23:50:03 +0300 Subject: [PATCH 18/62] Fix send waiting in check latest release tests --- .../AppCenterTests/MSChannelDefaultTests.m | 2 +- .../Internals/Sender/MSDistributeSender.m | 2 +- .../MSDistributeTests.m | 71 ++++++++++++------- 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/AppCenter/AppCenterTests/MSChannelDefaultTests.m b/AppCenter/AppCenterTests/MSChannelDefaultTests.m index 1362151864..87196b8dab 100644 --- a/AppCenter/AppCenterTests/MSChannelDefaultTests.m +++ b/AppCenter/AppCenterTests/MSChannelDefaultTests.m @@ -384,7 +384,7 @@ - (void)testNextBatchSentIfPendingQueueGotRoomAgain { id senderMock = OCMProtocolMock(@protocol(MSSender)); OCMStub([senderMock sendAsync:OCMOCK_ANY completionHandler:OCMOCK_ANY]).andDo(^(NSInvocation *invocation) { - // Get sender bloc for later call. + // Get sender block for later call. [invocation retainArguments]; [invocation getArgument:&senderBlock atIndex:3]; [invocation getArgument:&lastBatchLogContainer atIndex:2]; diff --git a/AppCenterDistribute/AppCenterDistribute/Internals/Sender/MSDistributeSender.m b/AppCenterDistribute/AppCenterDistribute/Internals/Sender/MSDistributeSender.m index 9b4adb6c1a..6eb1f335a7 100644 --- a/AppCenterDistribute/AppCenterDistribute/Internals/Sender/MSDistributeSender.m +++ b/AppCenterDistribute/AppCenterDistribute/Internals/Sender/MSDistributeSender.m @@ -33,7 +33,7 @@ - (id)initWithBaseUrl:(NSString *)baseUrl queryStrings:queryStrings reachability:[MS_Reachability reachabilityForInternetConnection] retryIntervals:@[ @(10), @(5 * 60), @(20 * 60) ]])) { - self.appSecret = [[MSDistribute sharedInstance] appSecret]; + _appSecret = appSecret; } return self; diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 6b46258901..345e6e32e0 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -12,6 +12,8 @@ #import "MSHttpTestUtil.h" #import "MSKeychainUtil.h" #import "MSMockUserDefaults.h" +#import "MSLogger.h" +#import "MSSenderCall.h" #import "MSServiceAbstractProtected.h" #import "MSTestFrameworks.h" #import "MSUserDefaults.h" @@ -62,6 +64,12 @@ - (void)openURL:(NSURL *)url @end +@interface MSSenderCall () + +- (void)startTimer; + +@end + static NSURL *sfURL; @interface MSDistributeTests : XCTestCase @@ -78,6 +86,7 @@ @implementation MSDistributeTests - (void)setUp { [super setUp]; + [MSLogger setCurrentLogLevel:MSLogLevelVerbose]; [MSKeychainUtil clear]; self.sut = [MSDistribute new]; self.settingsMock = [MSMockUserDefaults new]; @@ -464,7 +473,6 @@ - (void)testShowConfirmationAlert { // If NSString *appName = @"Test App"; OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleDisplayName"]).andReturn(appName); - id appCenterMock = OCMPartialMock(self.sut); MSReleaseDetails *details = [MSReleaseDetails new]; details.shortVersion = @"2.5"; details.version = @"11"; @@ -480,7 +488,7 @@ - (void)testShowConfirmationAlert { // When XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert has been displayed"]; - [appCenterMock showConfirmationAlert:details]; + [self.sut showConfirmationAlert:details]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); @@ -504,7 +512,6 @@ - (void)testShowConfirmationAlert { OCMVerify([self.alertControllerMock addPreferredActionWithTitle:OCMOCK_ANY handler:OCMOCK_ANY]); }]; - [appCenterMock stopMocking]; } - (void)testShowConfirmationAlertWithoutViewReleaseNotesButton { @@ -512,7 +519,6 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButton { // If NSString *appName = @"Test App"; OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleDisplayName"]).andReturn(appName); - id appCenterMock = OCMPartialMock(self.sut); OCMReject([self.alertControllerMock addDefaultActionWithTitle:MSDistributeLocalizedString(@"MSDistributeViewReleaseNotes") handler:OCMOCK_ANY]); @@ -529,7 +535,7 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButton { // When XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert has been displayed"]; - [appCenterMock showConfirmationAlert:details]; + [self.sut showConfirmationAlert:details]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); @@ -550,7 +556,6 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButton { handler:OCMOCK_ANY]); OCMVerifyAll(self.alertControllerMock); }]; - [appCenterMock stopMocking]; } - (void)testShowConfirmationAlertForMandatoryUpdate { @@ -558,7 +563,6 @@ - (void)testShowConfirmationAlertForMandatoryUpdate { // If NSString *appName = @"Test App"; OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleDisplayName"]).andReturn(appName); - id appCenterMock = OCMPartialMock(self.sut); OCMReject([self.alertControllerMock addDefaultActionWithTitle:MSDistributeLocalizedString(@"MSDistributeAskMeInADay") handler:OCMOCK_ANY]); MSReleaseDetails *details = [MSReleaseDetails new]; @@ -576,7 +580,7 @@ - (void)testShowConfirmationAlertForMandatoryUpdate { // When XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert has been displayed"]; - [appCenterMock showConfirmationAlert:details]; + [self.sut showConfirmationAlert:details]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); @@ -598,7 +602,6 @@ - (void)testShowConfirmationAlertForMandatoryUpdate { handler:OCMOCK_ANY]); OCMVerifyAll(self.alertControllerMock); }]; - [appCenterMock stopMocking]; } - (void)testShowConfirmationAlertWithoutViewReleaseNotesButtonForMandatoryUpdate { @@ -606,7 +609,6 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButtonForMandatoryUpdate // If NSString *appName = @"Test App"; OCMStub([self.bundleMock objectForInfoDictionaryKey:@"CFBundleDisplayName"]).andReturn(appName); - id appCenterMock = OCMPartialMock(self.sut); OCMReject([self.alertControllerMock addDefaultActionWithTitle:MSDistributeLocalizedString(@"MSDistributeAskMeInADay") handler:OCMOCK_ANY]); OCMReject([self.alertControllerMock @@ -625,7 +627,7 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButtonForMandatoryUpdate // When XCTestExpectation *expection = [self expectationWithDescription:@"Confirmation alert has been displayed"]; - [appCenterMock showConfirmationAlert:details]; + [self.sut showConfirmationAlert:details]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); @@ -643,7 +645,6 @@ - (void)testShowConfirmationAlertWithoutViewReleaseNotesButtonForMandatoryUpdate handler:OCMOCK_ANY]); OCMVerifyAll(self.alertControllerMock); }]; - [appCenterMock stopMocking]; } - (void)testShowConfirmationAlertForMandatoryUpdateWhileNoNetwork { @@ -838,10 +839,23 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { // If id distributeMock = OCMPartialMock(self.sut); OCMReject([distributeMock handleUpdate:OCMOCK_ANY]); + self.sut.appSecret = kMSTestAppSecret; id keychainMock = OCMClassMock([MSKeychainUtil class]); id reachabilityMock = OCMClassMock([MS_Reachability class]); OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); + XCTestExpectation *expection = [self expectationWithDescription:@"Request completed."]; + id senderCallMock = OCMPartialMock([MSSenderCall alloc]); + OCMStub([senderCallMock alloc]).andReturn(senderCallMock); + OCMReject([senderCallMock startTimer]); + OCMStub([senderCallMock sender:OCMOCK_ANY + callCompletedWithStatus:MSHTTPCodesNo404NotFound + data:OCMOCK_ANY + error:OCMOCK_ANY]) + .andForwardToRealObject() + .andDo(^(__unused NSInvocation *invocation) { + [expection fulfill]; + }); // Non recoverable error. [MSHttpTestUtil stubHttp404Response]; @@ -852,15 +866,12 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { releaseHash:@"releaseHash"]; // Then - XCTestExpectation *expection = [self expectationWithDescription:@"checkLatestRelease"]; - dispatch_async(dispatch_get_main_queue(), ^{ - [expection fulfill]; - }); [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { // Then OCMVerifyAll(distributeMock); + OCMVerifyAll(senderCallMock); OCMVerify([keychainMock deleteStringForKey:kMSUpdateTokenKey]); OCMVerify([self.settingsMock removeObjectForKey:kMSSDKHasLaunchedWithDistribute]); OCMVerify([self.settingsMock removeObjectForKey:kMSUpdateTokenRequestIdKey]); @@ -879,6 +890,7 @@ - (void)testCheckLatestReleaseRemoveKeysOnNonRecoverableError { [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; + [senderCallMock stopMocking]; } - (void)testCheckLatestReleaseOnRecoverableError { @@ -886,11 +898,24 @@ - (void)testCheckLatestReleaseOnRecoverableError { // If id distributeMock = OCMPartialMock(self.sut); OCMReject([distributeMock handleUpdate:OCMOCK_ANY]); + self.sut.appSecret = kMSTestAppSecret; id keychainMock = OCMClassMock([MSKeychainUtil class]); OCMReject([keychainMock deleteStringForKey:kMSUpdateTokenKey]); id reachabilityMock = OCMClassMock([MS_Reachability class]); OCMStub([reachabilityMock reachabilityForInternetConnection]).andReturn(reachabilityMock); OCMStub([reachabilityMock currentReachabilityStatus]).andReturn(ReachableViaWiFi); + XCTestExpectation *expection = [self expectationWithDescription:@"Request completed."]; + id senderCallMock = OCMPartialMock([MSSenderCall alloc]); + OCMStub([senderCallMock alloc]).andReturn(senderCallMock); + OCMStub([senderCallMock startTimer]).andDo(nil); + OCMStub([senderCallMock sender:OCMOCK_ANY + callCompletedWithStatus:MSHTTPCodesNo500InternalServerError + data:OCMOCK_ANY + error:OCMOCK_ANY]) + .andForwardToRealObject() + .andDo(^(__unused NSInvocation *invocation) { + [expection fulfill]; + }); // Recoverable error. [MSHttpTestUtil stubHttp500Response]; @@ -905,16 +930,13 @@ - (void)testCheckLatestReleaseOnRecoverableError { releaseHash:@"releaseHash"]; // Then - XCTestExpectation *expection = [self expectationWithDescription:@"checkLatestRelease"]; - dispatch_async(dispatch_get_main_queue(), ^{ - [expection fulfill]; - }); [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) { // Then OCMVerifyAll(distributeMock); OCMVerifyAll(keychainMock); + OCMVerify([senderCallMock startTimer]); XCTAssertNotNil([self.settingsMock objectForKey:kMSSDKHasLaunchedWithDistribute]); XCTAssertNotNil([self.settingsMock objectForKey:kMSUpdateTokenRequestIdKey]); XCTAssertNotNil([self.settingsMock objectForKey:kMSPostponedTimestampKey]); @@ -928,6 +950,7 @@ - (void)testCheckLatestReleaseOnRecoverableError { [distributeMock stopMocking]; [keychainMock stopMocking]; [reachabilityMock stopMocking]; + [senderCallMock stopMocking]; } - (void)testPersistLastestMandatoryUpdate { @@ -1547,7 +1570,7 @@ - (void)testDismissEmbeddedSafariWhenOpenURL { id distributeMock = OCMPartialMock(self.sut); OCMStub([distributeMock sharedInstance]).andReturn(distributeMock); OCMStub([distributeMock isEnabled]).andReturn(YES); - ((MSDistribute *)distributeMock).appSecret = kMSTestAppSecret; + self.sut.appSecret = kMSTestAppSecret; [MS_USER_DEFAULTS setObject:@"FIRST-REQUEST" forKey:kMSUpdateTokenRequestIdKey]; NSDictionary *plist = @{ @"CFBundleShortVersionString" : @"1.0", @"CFBundleVersion" : @"1" }; OCMStub([self.bundleMock infoDictionary]).andReturn(plist); @@ -1604,12 +1627,9 @@ - (void)testDismissEmbeddedSafariWhenDisabling { - (void)testShowDistributeDisabledAlert { - // If - id appCenterMock = OCMPartialMock(self.sut); - // When XCTestExpectation *expection = [self expectationWithDescription:@"Distribute disabled alert has been displayed"]; - [appCenterMock showDistributeDisabledAlert]; + [self.sut showDistributeDisabledAlert]; dispatch_async(dispatch_get_main_queue(), ^{ [expection fulfill]; }); @@ -1622,7 +1642,6 @@ - (void)testShowDistributeDisabledAlert { OCMVerify( [self.alertControllerMock addCancelActionWithTitle:OCMOCK_ANY handler:OCMOCK_ANY]); }]; - [appCenterMock stopMocking]; } - (void)testStartDownload { From a8c7cf220f24cdd4f214ed324d44cdbc8db4e3ec Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Wed, 15 Nov 2017 18:26:52 -0800 Subject: [PATCH 19/62] 1.0.1 -> 1.0.2 --- Config/Version.xcconfig | 2 +- Documentation/iOS/AppCenter/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterCrashes/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterDistribute/.jazzy.yaml | 2 +- Documentation/iOS/AppCenterPush/.jazzy.yaml | 2 +- Documentation/macOS/AppCenter/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterCrashes/.jazzy.yaml | 2 +- Documentation/macOS/AppCenterPush/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenter/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml | 2 +- Documentation/tvOS/AppCenterCrashes/.jazzy.yaml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Config/Version.xcconfig b/Config/Version.xcconfig index cf13071e70..2dfef5e63a 100644 --- a/Config/Version.xcconfig +++ b/Config/Version.xcconfig @@ -1,2 +1,2 @@ BUILD_NUMBER = 1 -VERSION_STRING = 1.0.1 +VERSION_STRING = 1.0.2 diff --git a/Documentation/iOS/AppCenter/.jazzy.yaml b/Documentation/iOS/AppCenter/.jazzy.yaml index 62e8d5d9dd..e0573e580c 100644 --- a/Documentation/iOS/AppCenter/.jazzy.yaml +++ b/Documentation/iOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenter -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml index e88afb7084..c21c73815c 100644 --- a/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/iOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterCrashes/.jazzy.yaml b/Documentation/iOS/AppCenterCrashes/.jazzy.yaml index aa2334ab2f..b8fd837a93 100644 --- a/Documentation/iOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/iOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterDistribute/.jazzy.yaml b/Documentation/iOS/AppCenterDistribute/.jazzy.yaml index 1628348eed..48c41380b3 100644 --- a/Documentation/iOS/AppCenterDistribute/.jazzy.yaml +++ b/Documentation/iOS/AppCenterDistribute/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterDistribute -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/iOS/AppCenterPush/.jazzy.yaml b/Documentation/iOS/AppCenterPush/.jazzy.yaml index bfe4cfca80..c5c60c841d 100644 --- a/Documentation/iOS/AppCenterPush/.jazzy.yaml +++ b/Documentation/iOS/AppCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: iphonesimulator theme: ../../Themes/apple module: AppCenterPush -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenter/.jazzy.yaml b/Documentation/macOS/AppCenter/.jazzy.yaml index 89300efd32..efb6eaead5 100644 --- a/Documentation/macOS/AppCenter/.jazzy.yaml +++ b/Documentation/macOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenter -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml index 447f294aca..d67d527063 100644 --- a/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/macOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterCrashes/.jazzy.yaml b/Documentation/macOS/AppCenterCrashes/.jazzy.yaml index 33dda23b8b..6d0bfd83ba 100644 --- a/Documentation/macOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/macOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/macOS/AppCenterPush/.jazzy.yaml b/Documentation/macOS/AppCenterPush/.jazzy.yaml index 01cae40913..f3e1cab331 100644 --- a/Documentation/macOS/AppCenterPush/.jazzy.yaml +++ b/Documentation/macOS/AppCenterPush/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: macosx theme: ../../Themes/apple module: AppCenterPush -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenter/.jazzy.yaml b/Documentation/tvOS/AppCenter/.jazzy.yaml index 71ab5f7db3..b964a6d444 100644 --- a/Documentation/tvOS/AppCenter/.jazzy.yaml +++ b/Documentation/tvOS/AppCenter/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenter -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml b/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml index a1e0f3eb43..16c1c3f861 100644 --- a/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml +++ b/Documentation/tvOS/AppCenterAnalytics/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenterAnalytics -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com diff --git a/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml b/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml index ac0e99c59f..e2276d14ce 100644 --- a/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml +++ b/Documentation/tvOS/AppCenterCrashes/.jazzy.yaml @@ -5,7 +5,7 @@ sdk: appletvsimulator theme: ../../Themes/apple module: AppCenterCrashes -module_version: 1.0.1 +module_version: 1.0.2 author: Microsoft Corp author_url: http://www.microsoft.com From f7dd3aa8021eba6eb2b9a38e823be90824e7ecc4 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Thu, 16 Nov 2017 22:49:56 +0300 Subject: [PATCH 20/62] Wrap removeAllStubs in MSHttpTestUtil --- AppCenter/AppCenterTests/MSIngestionSenderTests.m | 2 +- AppCenter/AppCenterTests/Util/MSHttpTestUtil.h | 2 +- AppCenter/AppCenterTests/Util/MSHttpTestUtil.m | 5 +++++ .../AppCenterDistributeTests/MSDistributeTests.m | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AppCenter/AppCenterTests/MSIngestionSenderTests.m b/AppCenter/AppCenterTests/MSIngestionSenderTests.m index dffc20fe9e..1d553480cc 100644 --- a/AppCenter/AppCenterTests/MSIngestionSenderTests.m +++ b/AppCenter/AppCenterTests/MSIngestionSenderTests.m @@ -54,7 +54,7 @@ - (void)setUp { - (void)tearDown { [super tearDown]; - [OHHTTPStubs removeAllStubs]; + [MSHttpTestUtil removeAllStubs]; /* * Setting the variable to nil. We are experiencing test failure on Xcode 9 beta because the instance that was used diff --git a/AppCenter/AppCenterTests/Util/MSHttpTestUtil.h b/AppCenter/AppCenterTests/Util/MSHttpTestUtil.h index 782577dbd1..6350f4acfb 100644 --- a/AppCenter/AppCenterTests/Util/MSHttpTestUtil.h +++ b/AppCenter/AppCenterTests/Util/MSHttpTestUtil.h @@ -1,5 +1,4 @@ #import -#import @interface MSHttpTestUtil : NSObject @@ -8,5 +7,6 @@ + (void)stubHttp200Response; + (void)stubNetworkDownResponse; + (void)stubLongTimeOutResponse; ++ (void)removeAllStubs; @end diff --git a/AppCenter/AppCenterTests/Util/MSHttpTestUtil.m b/AppCenter/AppCenterTests/Util/MSHttpTestUtil.m index a00da46ce0..66d3cfab7c 100644 --- a/AppCenter/AppCenterTests/Util/MSHttpTestUtil.m +++ b/AppCenter/AppCenterTests/Util/MSHttpTestUtil.m @@ -1,3 +1,4 @@ +#import #import "MSConstants+Internal.h" #import "MSHttpTestUtil.h" @@ -28,6 +29,10 @@ + (void)stubHttp200Response { [[self class] stubResponseWithCode:MSHTTPCodesNo200OK name:kMSStub200Name]; } ++ (void)removeAllStubs { + [OHHTTPStubs removeAllStubs]; +} + + (void)stubNetworkDownResponse { NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:kCFURLErrorNotConnectedToInternet userInfo:nil]; [[self class] stubResponseWithError:error name:kMSStubNetworkDownName]; diff --git a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m index 96448ba4f2..c3f22dbecd 100644 --- a/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m +++ b/AppCenterDistribute/AppCenterDistributeTests/MSDistributeTests.m @@ -116,7 +116,7 @@ - (void)tearDown { [self waitForExpectations:@[ expection ] timeout:1]; // Clear - [OHHTTPStubs removeAllStubs]; + [MSHttpTestUtil removeAllStubs]; [MSKeychainUtil clear]; [self.parserMock stopMocking]; [self.settingsMock stopMocking]; From 7342cd8d460f28a4844bdfaaee8a6689b9a5a616 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Fri, 17 Nov 2017 17:29:49 +0300 Subject: [PATCH 21/62] Fix process crashes test --- .../AppCenterCrashesTests/MSCrashesTests.mm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm index 63f1979925..bed77eb931 100644 --- a/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm +++ b/AppCenterCrashes/AppCenterCrashesTests/MSCrashesTests.mm @@ -205,6 +205,7 @@ - (void)testProcessCrashes { dispatch_group_wait(self.sut.bufferFileGroup, DISPATCH_TIME_FOREVER); // If + NSString *crashesPath = [self.sut.crashesDir path]; self.sut = OCMPartialMock(self.sut); OCMStub([self.sut startDelayedCrashProcessing]).andDo(nil); @@ -231,6 +232,8 @@ - (void)testProcessCrashes { // Then assertThat(self.sut.crashFiles, hasCountOf(1)); + assertThatLong([self.sut.fileManager contentsOfDirectoryAtPath:crashesPath error:nil].count, + equalToLong(1)); // When self.sut = OCMPartialMock([MSCrashes new]); @@ -241,12 +244,15 @@ - (void)testProcessCrashes { }; self.sut.userConfirmationHandler = userConfirmationHandlerYES; + [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; [self.sut startCrashProcessing]; [self.sut notifyWithUserConfirmation:MSUserConfirmationDontSend]; self.sut.userConfirmationHandler = nil; // Then assertThat(self.sut.crashFiles, hasCountOf(0)); + assertThatLong([self.sut.fileManager contentsOfDirectoryAtPath:crashesPath error:nil].count, + equalToLong(0)); // When self.sut = OCMPartialMock([MSCrashes new]); @@ -256,6 +262,8 @@ - (void)testProcessCrashes { // Then assertThat(self.sut.crashFiles, hasCountOf(1)); + assertThatLong([self.sut.fileManager contentsOfDirectoryAtPath:crashesPath error:nil].count, + equalToLong(1)); // When self.sut = OCMPartialMock([MSCrashes new]); @@ -265,10 +273,13 @@ - (void)testProcessCrashes { return NO; }; self.sut.userConfirmationHandler = userConfirmationHandlerNO; + [self.sut startWithLogManager:OCMProtocolMock(@protocol(MSLogManager)) appSecret:kMSTestAppSecret]; [self.sut startCrashProcessing]; // Then assertThat(self.sut.crashFiles, hasCountOf(0)); + assertThatLong([self.sut.fileManager contentsOfDirectoryAtPath:crashesPath error:nil].count, + equalToLong(0)); } - (void)testProcessCrashesWithErrorAttachments { From dd23fab85bce286644eb3d6bb15eba7a58d8dc25 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Fri, 17 Nov 2017 22:33:19 +0300 Subject: [PATCH 22/62] Add comment about delegate queue concurrency --- AppCenter/AppCenter/Internals/Sender/MSHttpSender.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m b/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m index b8021c7d93..84b67e3a17 100644 --- a/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m +++ b/AppCenter/AppCenter/Internals/Sender/MSHttpSender.m @@ -351,6 +351,12 @@ - (NSURLSession *)session { NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfiguration.timeoutIntervalForRequest = kRequestTimeout; _session = [NSURLSession sessionWithConfiguration:sessionConfiguration]; + + /* + * Limit callbacks execution concurrency to avoid race condition. This queue is used only for + * delegate method calls and completion handlers. + * See https://developer.apple.com/documentation/foundation/nsurlsession/1411571-delegatequeue + */ _session.delegateQueue.maxConcurrentOperationCount = 1; } return _session; From 26bb97b8e00a31b88f205ee5e7b8d6bde362afb7 Mon Sep 17 00:00:00 2001 From: Jae Lim Date: Wed, 22 Nov 2017 12:36:17 -0800 Subject: [PATCH 23/62] Add build scripts for VSTS --- vsts/appcenter-build.sh | 30 ++++ vsts/commit-validation.sh | 8 ++ vsts/internal-version-increment.sh | 62 ++++++++ vsts/publish-podspec.sh | 122 ++++++++++++++++ vsts/publish.sh | 218 +++++++++++++++++++++++++++++ vsts/zip.sh | 10 ++ 6 files changed, 450 insertions(+) create mode 100755 vsts/appcenter-build.sh create mode 100755 vsts/commit-validation.sh create mode 100755 vsts/internal-version-increment.sh create mode 100755 vsts/publish-podspec.sh create mode 100755 vsts/publish.sh create mode 100755 vsts/zip.sh diff --git a/vsts/appcenter-build.sh b/vsts/appcenter-build.sh new file mode 100755 index 0000000000..d301466bd1 --- /dev/null +++ b/vsts/appcenter-build.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +help() { + echo "Usage: $0 -t " +} + +## I. Check parameter +APP_CENTER_ACCESS_TOKEN="" +while getopts 't:' flag; do + case "${flag}" in + t) + APP_CENTER_ACCESS_TOKEN=${OPTARG} + ;; + *) + help + exit 1 + ;; + esac +done + +if [ "$APP_CENTER_ACCESS_TOKEN" == "" ]; then + help + exit 1 +fi + +## II. Run App Center Build +$APP_CENTER_CLI_COMMNAD build queue --token $APP_CENTER_ACCESS_TOKEN --branch $BUILD_SOURCEBRANCHNAME --app $APP_CENTER_SASQUATCHOBJC_BUILD_APP_ID +$APP_CENTER_CLI_COMMNAD build queue --token $APP_CENTER_ACCESS_TOKEN --branch $BUILD_SOURCEBRANCHNAME --app $APP_CENTER_SASQUATCHSWIFT_BUILD_APP_ID +$APP_CENTER_CLI_COMMNAD build queue --token $APP_CENTER_ACCESS_TOKEN --branch $BUILD_SOURCEBRANCHNAME --app $APP_CENTER_SASQUATCHMACOBJC_BUILD_APP_ID +$APP_CENTER_CLI_COMMNAD build queue --token $APP_CENTER_ACCESS_TOKEN --branch $BUILD_SOURCEBRANCHNAME --app $APP_CENTER_SASQUATCHMACSWIFT_BUILD_APP_ID \ No newline at end of file diff --git a/vsts/commit-validation.sh b/vsts/commit-validation.sh new file mode 100755 index 0000000000..61659e5ee3 --- /dev/null +++ b/vsts/commit-validation.sh @@ -0,0 +1,8 @@ +#!/bin/bash +if [ -z "$1" ]; then + echo "This build doesn't have an associated commit hash which is required." + echo "If this is an ad hoc build, please specify an appropriate commit hash for the build" + exit 1 +else + echo "Found commit hash:" $1 +fi diff --git a/vsts/internal-version-increment.sh b/vsts/internal-version-increment.sh new file mode 100755 index 0000000000..d7a082ef2b --- /dev/null +++ b/vsts/internal-version-increment.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +help() { + echo "Usage: $0 -a -k " +} + +## I. Check Parameters +while getopts 'a:k:' flag; do + case "${flag}" in + a) + export AZURE_STORAGE_ACCOUNT=${OPTARG} + ;; + k) + export AZURE_STORAGE_ACCESS_KEY=${OPTARG} + ;; + *) + help + exit 1 + ;; + esac +done + +if [ "$AZURE_STORAGE_ACCOUNT" == "" ] || [ "$AZURE_STORAGE_ACCESS_KEY" == "" ]; then + help + exit 1 +fi + +## II. Get the latest version +echo "Get the latest version to determine a build number" +publish_version="$(grep "VERSION_STRING" $VERSION_FILENAME | head -1 | awk -F "[= ]" '{print $4}')" +build_number=0 +resp="$(curl -s $INTERNAL_RELEASE_VERSION_FILENAME)" +version="$(echo $resp | jq -r '.version')" + +# Exit if response doesn't contain an array +if [ -z $version ] || [ "$version" == "" ] || [ "$version" == "null" ]; then + echo "Cannot retrieve the latest version" + echo "Response:" $resp + exit 1 +fi + +# Determine the next version +if [[ "$version" == $publish_version-* ]]; then + build_number="$(echo $version | awk -F "[-]" '{print $2}')" + build_number=$(($build_number + 1)) +fi + +publish_version=$publish_version-$build_number +echo "New version:" $publish_version +echo "##vso[task.setvariable variable=SDK_PUBLISH_VERSION]$publish_version" + +## III. Update version file +echo {\"version\":\"$publish_version\"} > $AZURE_APPLE_VERSION_FILE +azure telemetry --disable +echo "Y" | azure storage blob upload $AZURE_APPLE_VERSION_FILE sdk +rm $AZURE_APPLE_VERSION_FILE + +## IV. Update version for frameworks + +if [ "$BUILD_SOURCEBRANCHNAME" != "master" ]; then + sed "s/\(VERSION_STRING[[:space:]]*=[[:space:]]*\).*/\1$publish_version/g" $VERSION_FILENAME > $VERSION_FILENAME.tmp; mv $VERSION_FILENAME.tmp $VERSION_FILENAME +fi diff --git a/vsts/publish-podspec.sh b/vsts/publish-podspec.sh new file mode 100755 index 0000000000..0a265f70a3 --- /dev/null +++ b/vsts/publish-podspec.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +help() { + echo "Usage: $0 {internal|external|test} -a -t -r " +} + +## I. Check parameter +if [ -z $1 ] || ( [ "$1" != "internal" ] && [ "$1" != "external" ] && [ "$1" != "test" ] ); then + help + exit 1 +fi + +mode=$1 +shift +user_account="" +access_token="" +repo_name="" +while getopts 'a:t:r:' flag; do + case "${flag}" in + a) + user_account=${OPTARG} + ;; + t) + access_token=${OPTARG} + ;; + r) + repo_name=${OPTARG} + ;; + *) + help + exit 1 + ;; + esac +done + +if [ "$user_account" == "" ] || [ "$access_token" == "" ] || [ "$repo_name" == "" ]; then + help + exit 1 +fi + +## II. Add private pod spec repo + +if [ "$mode" == "test" ]; then + resp="$(pod repo add $repo_name https://$user_account:$access_token@msmobilecenter.visualstudio.com/SDK/_git/$repo_name)" +else + resp="$(pod repo add $repo_name https://$user_account:$access_token@github.com/$GITHUB_ORG_NAME/$repo_name.git)" +fi + +error="$(echo $resp | grep -i 'error\|fatal')" +if [ "$error" ]; then + echo "Couldn't add private spec repo for $mode" + exit 1 +fi + +## III. Get publish version for information +publish_version="$(grep "VERSION_STRING" $VERSION_FILENAME | head -1 | awk -F "[= ]" '{print $4}')" +echo "Publishing podspec for version" $publish_version + +if [ "$mode" == "internal" ] || [ "$mode" == "test" ]; then + + if [ "$mode" == "test" ]; then + + # Revert podspec change for other platforms + git revert $REVERT_COMMIT + + # Add build number to podspec version + sed "s/\(s\.version[[:space:]]*=[[:space:]]\)\'.*\'$/\1'$SDK_PUBLISH_VERSION'/1" AppCenter.podspec > AppCenter.podspec.tmp; mv AppCenter.podspec.tmp AppCenter.podspec + + # Change download URL in podspec + sed "s/https:\/\/github\.com\/microsoft\/AppCenter-SDK-Apple\/releases\/download\/#{s.version}\(\/AppCenter-SDK-Apple-\)\(\#{s.version}\)\(.zip\)/https:\/\/mobilecentersdkdev\.blob\.core\.windows\.net\/sdk\1\2+$BUILD_SOURCEVERSION\3/1" AppCenter.podspec > AppCenter.podspec.tmp; mv AppCenter.podspec.tmp AppCenter.podspec + + fi + + ## 1. Get path of internal podspec local repo + repo_path="$(pod repo | grep "$repo_name" | grep Path | head -1 | awk -F ": " '{print $2}')" + + ## 2. Update podspec to the internal podspec local repo + resp="$(pod repo push $repo_name $PODSPEC_FILENAME)" + + echo $resp + + # Check error from the response + error="$(echo $resp | grep -i 'error\|fatal')" + if [ "$error" ]; then + echo "Cannot publish to internal repo" + exit 1 + fi + + ## 3. Push podspec to the internal podspec remote repo + cd $repo_path + git push + cd $BITRISE_SOURCE_DIR + + echo "Podspec published to $mode repo successfully" + +else + + ## 1. Run lint to validate podspec. + resp="$(pod spec lint $PODSPEC_FILENAME)" + echo $resp + + # Check error from the response + error="$(echo $resp | grep -i 'error\|fatal')" + if [ "$error" ]; then + echo "Cannot publish to CocoaPods due to spec validation failure" + exit 1 + fi + + ## 2. Push podspec to CocoaPods + resp="$(pod trunk push $PODSPEC_FILENAME)" + echo $resp + + # Check error from the response + error="$(echo $resp | grep -i 'error\|fatal')" + if [ "$error" ]; then + echo "Cannot publish to CocoaPods" + exit 1 + fi + + echo "Podspec published to CocoaPods successfully" + +fi diff --git a/vsts/publish.sh b/vsts/publish.sh new file mode 100755 index 0000000000..c974a60bf2 --- /dev/null +++ b/vsts/publish.sh @@ -0,0 +1,218 @@ +#!/bin/bash + +help() { + echo "Usage: $0 {internal|external} -a -k -t " +} + +## I. Check parameters +if [ -z $1 ] || ( [ "$1" != "internal" ] && [ "$1" != "external" ] ); then + help + exit 1 +fi + +mode=$1 +shift +github_access_token="" + +while getopts 'a:k:t:' flag; do + case "${flag}" in + a) + export AZURE_STORAGE_ACCOUNT=${OPTARG} + ;; + k) + export AZURE_STORAGE_ACCESS_KEY=${OPTARG} + ;; + t) + github_access_token=${OPTARG} + ;; + *) + help + exit 1 + ;; + esac +done + +if [ "$AZURE_STORAGE_ACCOUNT" == "" ] || [ "$AZURE_STORAGE_ACCESS_KEY" == "" ] || [ "$github_access_token" == "" ]; then + help + exit 1 +fi + +## II. Constants +REPOSITORY="$(echo $BUILD_REPOSITORY_URI | awk -F "[:]" '{print $2}' | awk -F "[/]" '{print $4"/"$5}' | awk -F "[.]" '{print $1}')" +GITHUB_API_URL_TEMPLATE="https://%s.github.com/repos/%s/%s?access_token=%s%s" +GITHUB_API_HOST="api" +GITHUB_UPLOAD_HOST="uploads" +BINARY_FILE="AppCenter-SDK-Apple.zip" + +## III. GitHub API endpoints +REQUEST_URL_REF_TAG="$(printf $GITHUB_API_URL_TEMPLATE $GITHUB_API_HOST $REPOSITORY 'git/refs/tags' $github_access_token)" +REQUEST_URL_TAG="$(printf $GITHUB_API_URL_TEMPLATE $GITHUB_API_HOST $REPOSITORY 'git/tags' $github_access_token)" +REQUEST_REFERENCE_URL="$(printf $GITHUB_API_URL_TEMPLATE $GITHUB_API_HOST $REPOSITORY 'git/refs' $github_access_token)" +REQUEST_RELEASE_URL="$(printf $GITHUB_API_URL_TEMPLATE $GITHUB_API_HOST $REPOSITORY 'releases' $github_access_token)" +REQUEST_UPLOAD_URL_TEMPLATE="$(printf $GITHUB_API_URL_TEMPLATE $GITHUB_UPLOAD_HOST $REPOSITORY 'releases/{id}/assets' $github_access_token '&name={filename}')" + +## IV. Get publish version +publish_version="$(grep "VERSION_STRING" $VERSION_FILENAME | head -1 | awk -F "[= ]" '{print $4}')" +echo "Publish version:" $publish_version + +if [ "$mode" == "internal" ]; then + + ## Change publish version to internal version + publish_version=$SDK_PUBLISH_VERSION + echo "Detected internal release. Publish version is updated to " $publish_version + +else + + ## 0. Download prerelease binary + prerelease_prefix=$(echo $BINARY_FILE | sed 's/.zip/-'$PRERELEASE_VERSION'/g') + resp="$(echo "Y" | azure storage blob list sdk ${prerelease_prefix})" + prerelease="$(echo $resp | sed 's/.*data:[[:space:]]\('$prerelease_prefix'+.\{40\}\.zip\).*/\1/1')" + if [[ $prerelease != $prerelease_prefix+*.zip ]]; then + if [ -z $PRERELEASE_VERSION ]; then + echo "You didn't provide a prerelease version to the build." + echo "If you didn't provide the prerelease version, add PRERELEASE_VERSION as a key and version as a value in Variables." + else + echo "Cannot find ("$PRERELEASE_VERSION") in Azure Blob Storage. Make sure you have provided a prerelease version to the build." + fi + exit 1 + fi + commit_hash="$(echo $resp | sed 's/.*data:[[:space:]]'$prerelease_prefix'+\(.\{40\}\)\.zip.*/\1/1')" + echo "Y" | azure storage blob download sdk $prerelease + mv $prerelease $BINARY_FILE + + ## 1. Extract change log + change_log_found=false + change_log="" + while IFS='' read -r line || -n "$line" ]]; do + + # If it is reading change log for the version + if $change_log_found; then + + # If it reads end of change log for the version + if [[ "$line" =~ "___" ]]; then + break + + # Append the line + else + change_log="$change_log\n$line" + fi + + # If it didn't find changelog for the version + else + + # If it is the first line of change log for the version + if [[ "$line" =~ "## Version $publish_version" ]]; then + change_log="$line" + change_log_found=true + fi + fi + done < $CHANGE_LOG_FILENAME + echo "Change log:" "$change_log" + + ## 2. Create a tag + echo "Create a tag ($publish_version) for the commit ($commit_hash)" + resp="$(curl -s -X POST $REQUEST_URL_TAG -d '{ + "tag": "'${publish_version}'", + "message": "'${publish_version}'", + "type": "commit", + "object": "'${commit_hash}'" + }')" + sha="$(echo $resp | jq -r '.sha')" + + # Exit if response doesn't contain "sha" key + if [ -z $sha ] || [ "$sha" == "" ] || [ "$sha" == "null" ]; then + echo "Cannot create a tag" + echo "Response:" $resp + exit 1 + else + echo "A tag has been created with SHA ($sha)" + fi + + ## 3. Create a reference + echo "Create a reference for the tag ($publish_version)" + resp="$(curl -s -X POST $REQUEST_REFERENCE_URL -d '{ + "ref": "refs/tags/'${publish_version}'", + "sha": "'${sha}'" + }')" + ref="$(echo $resp | jq -r '.ref')" + + # Exit if response doesn't contain "ref" key + if [ -z $ref ] || [ "$ref" == "" ] || [ "$ref" == "null" ]; then + echo "Cannot create a reference" + echo "Response:" $resp + exit 1 + else + echo "A reference has been created to $ref" + fi + + ## 4. Create a release + echo "Create a release for the tag ($publish_version)" + resp="$(curl -s -X POST $REQUEST_RELEASE_URL -d '{ + "tag_name": "'${publish_version}'", + "target_commitish": "master", + "name": "'${publish_version}'", + "body": "'"$change_log"'", + "draft": true, + "prerelease": true + }')" + id="$(echo $resp | jq -r '.id')" + + # Exit if response doesn't contain "id" key + if [ -z $id ] || [ "$id" == "" ] || [ "$id" == "null" ]; then + echo "Cannot create a release" + echo "Response:" $resp + exit 1 + else + echo "A release has been created with ID ($id)" + fi + +fi + +## V. Upload binary +echo "Upload binaries" +if [ "$mode" == "internal" ]; then + + # Determine the filename for the release + filename=$(echo $BINARY_FILE | sed 's/.zip/-'${publish_version}'+'$BUILD_SOURCEVERSION'.zip/g') + + # Replace the latest binary in Azure Storage + echo "Y" | azure storage blob upload $BINARY_FILE sdk + + # Upload binary to Azure Storage + mv $BINARY_FILE $filename + resp="$(echo "N" | azure storage blob upload ${filename} sdk | grep overwrite)" + if [ "$resp" ]; then + echo "${filename} already exists" + exit 1 + fi + +else + + # Determine the filename for the release + filename=$(echo $BINARY_FILE | sed 's/.zip/-'${publish_version}'.zip/g') + + # Upload binary to Azure Storage + mv $BINARY_FILE $filename + resp="$(echo "N" | azure storage blob upload ${filename} sdk | grep overwrite)" + if [ "$resp" ]; then + echo "${filename} already exists" + exit 1 + fi + + # Upload binary to GitHub for external release + upload_url="$(echo $REQUEST_UPLOAD_URL_TEMPLATE | sed 's/{id}/'$id'/g')" + url="$(echo $upload_url | sed 's/{filename}/'${filename}'/g')" + resp="$(curl -s -X POST -H 'Content-Type: application/zip' --data-binary @$filename $url)" + id="$(echo $resp | jq -r '.id')" + + # Log error if response doesn't contain "id" key + if [ -z $id ] || [ "$id" == "" ] || [ "$id" == "null" ]; then + echo "Cannot upload" $file + echo "Request URL:" $url + echo "Response:" $resp + exit 1 + fi + +fi + +echo $filename "Uploaded successfully" diff --git a/vsts/zip.sh b/vsts/zip.sh new file mode 100755 index 0000000000..2fb9de7229 --- /dev/null +++ b/vsts/zip.sh @@ -0,0 +1,10 @@ +#!/bin/bash +folder=AppCenter-SDK-Apple/ + +# Copy LICENSE, README and CHANGELOG +cp LICENSE $folder +cp README.md $folder +cp CHANGELOG.md $folder + +# Zip the folder +zip -r $FRAMEWORKS_ZIP_FILENAME $folder From 9cf798b9e9c064b2502008fc81b1e9ced70b7794 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Thu, 23 Nov 2017 13:45:30 +0300 Subject: [PATCH 24/62] Fix launch screens on iPads --- .../AppIcon.appiconset/Contents.json | 5 ++ .../Puppet/Base.lproj/LaunchScreen.storyboard | 41 ++++++++---- Sasquatch/Sasquatch.xcodeproj/project.pbxproj | 20 ++++-- .../AppIcon.appiconset/Contents.json | 5 ++ .../Base.lproj/LaunchScreen.storyboard | 64 +++++++++++++++++++ .../Sasquatch/LaunchScreen.storyboard | 51 --------------- .../AppIcon.appiconset/Contents.json | 5 ++ .../AppIcon.appiconset/Contents.json | 5 ++ 8 files changed, 125 insertions(+), 71 deletions(-) create mode 100644 TestApps/Sasquatch/Sasquatch/Base.lproj/LaunchScreen.storyboard delete mode 100644 TestApps/Sasquatch/Sasquatch/LaunchScreen.storyboard diff --git a/Puppet/Puppet/Assets.xcassets/AppIcon.appiconset/Contents.json b/Puppet/Puppet/Assets.xcassets/AppIcon.appiconset/Contents.json index fbf2d4ee9a..c03333b330 100644 --- a/Puppet/Puppet/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Puppet/Puppet/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -101,6 +101,11 @@ "idiom" : "ipad", "filename" : "icon-16.png", "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/Puppet/Puppet/Base.lproj/LaunchScreen.storyboard b/Puppet/Puppet/Base.lproj/LaunchScreen.storyboard index 12349c400b..e7112e98c5 100644 --- a/Puppet/Puppet/Base.lproj/LaunchScreen.storyboard +++ b/Puppet/Puppet/Base.lproj/LaunchScreen.storyboard @@ -1,11 +1,13 @@ - - + + - + + + @@ -18,26 +20,37 @@ - + - - + + + + + + + + @@ -46,6 +59,6 @@ Puppet Test Application - + diff --git a/Sasquatch/Sasquatch.xcodeproj/project.pbxproj b/Sasquatch/Sasquatch.xcodeproj/project.pbxproj index 07ba93b1bb..ceb44145f7 100644 --- a/Sasquatch/Sasquatch.xcodeproj/project.pbxproj +++ b/Sasquatch/Sasquatch.xcodeproj/project.pbxproj @@ -12,8 +12,6 @@ 046790431E8DA7E90033FDEC /* AppCenterPush.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 046790411E8DA7D80033FDEC /* AppCenterPush.framework */; }; 047D13721EAFBDBE00D699BA /* AppCenterDistributeResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 047D13711EAFBDBE00D699BA /* AppCenterDistributeResources.bundle */; }; 048933631F8D395A00C38A87 /* Sasquatch.strings in Resources */ = {isa = PBXBuildFile; fileRef = 041A4BAF1F8C28A3009E1B6C /* Sasquatch.strings */; }; - 048EB9A11F86F4B7007620A0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 048EB9A01F86F4B7007620A0 /* LaunchScreen.storyboard */; }; - 048EB9A21F86F4B7007620A0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 048EB9A01F86F4B7007620A0 /* LaunchScreen.storyboard */; }; 5CE2587F1EA5F60200DA8FB9 /* DistributeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2587D1EA5F5FC00DA8FB9 /* DistributeUITests.swift */; }; 5CE258801EA5F60500DA8FB9 /* CrashesUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE2587B1EA5F5EB00DA8FB9 /* CrashesUITests.swift */; }; 5CE258811EA5F60900DA8FB9 /* AnalyticsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CE258791EA5F5DF00DA8FB9 /* AnalyticsUITests.swift */; }; @@ -76,6 +74,8 @@ D31EF96C1E9517C600450162 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31EF96B1E9517C600450162 /* NotificationController.swift */; }; D31EF96E1E9517C600450162 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D31EF96D1E9517C600450162 /* Assets.xcassets */; }; D31EF9721E9517C600450162 /* SasquatchWatchSwift.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = D31EF9541E9517C500450162 /* SasquatchWatchSwift.app */; }; + F809D5041FC6DA2B005E0F83 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F809D5021FC6DA2B005E0F83 /* LaunchScreen.storyboard */; }; + F809D5051FC6DD80005E0F83 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F809D5021FC6DA2B005E0F83 /* LaunchScreen.storyboard */; }; F89D79091E93DA3A0094521F /* CrashLibIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F89D79081E93DA3A0094521F /* CrashLibIOS.framework */; }; F89D790A1E93DA3A0094521F /* CrashLibIOS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F89D79081E93DA3A0094521F /* CrashLibIOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; F89D790C1E93DA500094521F /* CrashLibIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F89D79081E93DA3A0094521F /* CrashLibIOS.framework */; }; @@ -216,7 +216,6 @@ 046790441E8DA8D50033FDEC /* SasquatchSwift.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SasquatchSwift.entitlements; sourceTree = ""; }; 046790451E8DA8DD0033FDEC /* SasquatchObjC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SasquatchObjC.entitlements; sourceTree = ""; }; 047D13711EAFBDBE00D699BA /* AppCenterDistributeResources.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = AppCenterDistributeResources.bundle; path = "../AppCenter-SDK-Apple/iOS/AppCenterDistributeResources.bundle"; sourceTree = ""; }; - 048EB9A01F86F4B7007620A0 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 384929201FACF5DA003F8736 /* SasquatchWatchObjC Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SasquatchWatchObjC Extension.entitlements"; sourceTree = SOURCE_ROOT; }; 384929211FACF5F3003F8736 /* SasquatchWatchSwift Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SasquatchWatchSwift Extension.entitlements"; sourceTree = SOURCE_ROOT; }; 5CD700E51EA4B74500FC5D12 /* SasquatchSwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SasquatchSwiftUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -283,6 +282,7 @@ D31EF96B1E9517C600450162 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = ""; }; D31EF96D1E9517C600450162 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D31EF96F1E9517C600450162 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F809D5031FC6DA2B005E0F83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; F89D79081E93DA3A0094521F /* CrashLibIOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CrashLibIOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -459,8 +459,8 @@ 84226CB11E8909F700798417 /* Storyboards */ = { isa = PBXGroup; children = ( + F809D5021FC6DA2B005E0F83 /* LaunchScreen.storyboard */, 845964A91E8A7E6600BABA51 /* Main.storyboard */, - 048EB9A01F86F4B7007620A0 /* LaunchScreen.storyboard */, ); name = Storyboards; sourceTree = ""; @@ -855,7 +855,7 @@ 041A4BB11F8C28A3009E1B6C /* Sasquatch.strings in Resources */, 84226C561E88FF4A00798417 /* Assets.xcassets in Resources */, 047D13721EAFBDBE00D699BA /* AppCenterDistributeResources.bundle in Resources */, - 048EB9A11F86F4B7007620A0 /* LaunchScreen.storyboard in Resources */, + F809D5041FC6DA2B005E0F83 /* LaunchScreen.storyboard in Resources */, 845964AB1E8A7E6600BABA51 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -867,7 +867,7 @@ 048933631F8D395A00C38A87 /* Sasquatch.strings in Resources */, B27424851EF2193E00F591E5 /* AppCenterDistributeResources.bundle in Resources */, 84226C8A1E8908CA00798417 /* Assets.xcassets in Resources */, - 048EB9A21F86F4B7007620A0 /* LaunchScreen.storyboard in Resources */, + F809D5051FC6DD80005E0F83 /* LaunchScreen.storyboard in Resources */, 84D63FF91E8BAA90004C9F86 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1070,6 +1070,14 @@ name = Interface.storyboard; sourceTree = ""; }; + F809D5021FC6DA2B005E0F83 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F809D5031FC6DA2B005E0F83 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/TestApps/Sasquatch/Sasquatch/Assets.xcassets/AppIcon.appiconset/Contents.json b/TestApps/Sasquatch/Sasquatch/Assets.xcassets/AppIcon.appiconset/Contents.json index 1d060ed288..d8db8d65fd 100644 --- a/TestApps/Sasquatch/Sasquatch/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/TestApps/Sasquatch/Sasquatch/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -84,6 +84,11 @@ "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/TestApps/Sasquatch/Sasquatch/Base.lproj/LaunchScreen.storyboard b/TestApps/Sasquatch/Sasquatch/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..a5707ca83f --- /dev/null +++ b/TestApps/Sasquatch/Sasquatch/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TestApps/Sasquatch/Sasquatch/LaunchScreen.storyboard b/TestApps/Sasquatch/Sasquatch/LaunchScreen.storyboard deleted file mode 100644 index f56dafdb52..0000000000 --- a/TestApps/Sasquatch/Sasquatch/LaunchScreen.storyboard +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TestApps/Sasquatch/SasquatchObjC/Assets.xcassets/AppIcon.appiconset/Contents.json b/TestApps/Sasquatch/SasquatchObjC/Assets.xcassets/AppIcon.appiconset/Contents.json index fbf2d4ee9a..c03333b330 100644 --- a/TestApps/Sasquatch/SasquatchObjC/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/TestApps/Sasquatch/SasquatchObjC/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -101,6 +101,11 @@ "idiom" : "ipad", "filename" : "icon-16.png", "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/TestApps/Sasquatch/SasquatchSwift/Assets.xcassets/AppIcon.appiconset/Contents.json b/TestApps/Sasquatch/SasquatchSwift/Assets.xcassets/AppIcon.appiconset/Contents.json index fbf2d4ee9a..c03333b330 100644 --- a/TestApps/Sasquatch/SasquatchSwift/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/TestApps/Sasquatch/SasquatchSwift/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -101,6 +101,11 @@ "idiom" : "ipad", "filename" : "icon-16.png", "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { From 29b24ddb9f8740a24f838f598704d9c61574dfe5 Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Thu, 23 Nov 2017 14:37:47 +0300 Subject: [PATCH 25/62] Show crash detail as dialog in Puppet --- Puppet/Puppet/Base.lproj/Main.storyboard | 208 +++++++----------- Puppet/Puppet/MSCrashesDetailViewController.h | 13 -- Puppet/Puppet/MSCrashesDetailViewController.m | 29 --- Puppet/Puppet/MSCrashesViewController.m | 48 ++-- 4 files changed, 112 insertions(+), 186 deletions(-) delete mode 100644 Puppet/Puppet/MSCrashesDetailViewController.h delete mode 100644 Puppet/Puppet/MSCrashesDetailViewController.m diff --git a/Puppet/Puppet/Base.lproj/Main.storyboard b/Puppet/Puppet/Base.lproj/Main.storyboard index ba8133a857..7874f51fa1 100644 --- a/Puppet/Puppet/Base.lproj/Main.storyboard +++ b/Puppet/Puppet/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -29,14 +29,14 @@ - + @@ -81,7 +81,7 @@