Merge pull request #272 from Microsoft/feature/init-services-by-priority

Feature/init services by priority
This commit is contained in:
Jae Lim 2017-02-09 17:38:02 -08:00 коммит произвёл GitHub
Родитель f29b5604a3 8fb9033b5f
Коммит 6b907a92d5
11 изменённых файлов: 119 добавлений и 18 удалений

Просмотреть файл

@ -12,8 +12,6 @@
static NSString *const kMSInstallIdKey = @"MSInstallId";
static NSString *const kMSMobileCenterIsEnabledKey = @"MSMobileCenterIsEnabled";
@class MSService;
@interface MSMobileCenter ()
@property(nonatomic) id<MSLogManager> logManager;
@ -57,4 +55,12 @@ static NSString *const kMSMobileCenterIsEnabledKey = @"MSMobileCenterIsEnabled";
*/
+ (NSString *)logTag;
@end
/**
* Sort the array of services in descending order based on their priority.
*
* @return The array of services in descending order.
*/
- (NSArray *)sortServices:(NSArray<Class> *)services;
@end

Просмотреть файл

@ -8,7 +8,7 @@
NS_ASSUME_NONNULL_BEGIN
/**
* Protocol declaring services common logic.
* Protocol declaring public common logic for services.
*/
@protocol MSServiceCommon <NSObject>
@ -52,6 +52,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, readonly) MSPriority priority;
/**
* The initialization priority for this service.
*/
@property(nonatomic, readonly) MSInitializationPriority initializationPriority;
/**
* Get the unique instance.
*

Просмотреть файл

@ -8,6 +8,9 @@
/**
* Protocol declaring all the logic of a service. This is what concrete services needs to conform to.
* The difference is that MSServiceCommon is public, while MSServiceInternal is private.
* Some properties are present in both, which is counter-intuitive but the way we implemented this
* to achieve abstraction and not have empty implementations in MSServiceAbstract.
*/
@protocol MSServiceInternal <MSService, MSServiceCommon>
@ -19,10 +22,15 @@
@property(nonatomic, copy, readonly) NSString *storageKey;
/**
* The channel priority for this service.
* The channel priority for this service. Defined here as well as in MSServiceCommon to achieve abstraction.
*/
@property(nonatomic, readonly) MSPriority priority;
/**
* The initialization priority for this service. Defined here as well as in MSServiceCommon to achieve abstraction.
*/
@property(nonatomic, readonly) MSInitializationPriority initializationPriority;
/**
* The app secret for the SDK.
*/
@ -31,7 +39,7 @@
/**
* Get the unique instance.
*
* @return unique instance.
* @return The unique instance.
*/
+ (instancetype)sharedInstance;

Просмотреть файл

@ -17,10 +17,22 @@ static NSString *const kMSContentType = @"application/json";
static NSString *const kMSAPIVersion = @"1.0.0-preview20160914";
static NSString *const kMSAPIVersionKey = @"api_version";
// Channel priorities, check the kMSPriorityCount if you add a new value.
typedef NS_ENUM(NSInteger, MSPriority) { MSPriorityDefault, MSPriorityBackground, MSPriorityHigh };
/** Channel priorities, check the kMSPriorityCount if you add a new value.
* The order matters here! Values NEED to range from low priority to high priority.
*/
typedef NS_ENUM(NSInteger, MSPriority) { MSPriorityBackground, MSPriorityDefault, MSPriorityHigh };
static short const kMSPriorityCount = MSPriorityHigh + 1;
/**
* The priority by which the modules are initialized.
* MSPriorityMax is reserved for only 1 module and this needs to be Crashes. Crashes needs to be initialized first to
* catch crashes in our other SDK Modules (which will hopefully never happen) and to avoid losing any log at crash time.
*/
typedef NS_ENUM(NSInteger, MSInitializationPriority) { MSInitializationPriorityDefault = 500, MSInitializationPriorityMax = 999 };
/**
* Enum with the different HTTP status codes.
*/
typedef NS_ENUM(NSInteger, MSHTTPCodesNo) {
// Informational
MSHTTPCodesNo1XXInformationalUnknown = 1,

Просмотреть файл

@ -176,12 +176,35 @@ static NSString *const kMSDefaultBaseUrl = @"https://in.mobile.azure.com";
- (void)start:(NSString *)appSecret withServices:(NSArray<Class> *)services {
BOOL configured = [self configure:appSecret];
if (configured) {
for (Class service in services) {
NSArray *sortedServices = [self sortServices:services];
for (Class service in sortedServices) {
[self startService:service];
}
}
}
- (NSArray *)sortServices:(NSArray<Class> *)services {
// Sort services in descending order to make sure the service with the highest priority gets initialized first.
// This is intended to make sure Crashes gets initialized first.
if (services && services.count > 1) {
return [services sortedArrayUsingComparator:^NSComparisonResult(Class clazzA, Class clazzB) {
id <MSServiceInternal> serviceA = [clazzA sharedInstance];
id <MSServiceInternal> serviceB = [clazzB sharedInstance];
if (serviceA.initializationPriority < serviceB.initializationPriority) {
return NSOrderedDescending;
}
else {
return NSOrderedAscending;
}
}];
} else {
return services;
}
}
- (void)startService:(Class)clazz {
id<MSServiceInternal> service = [clazz sharedInstance];

Просмотреть файл

@ -2,8 +2,10 @@
#import "MSMobileCenter.h"
#import "MSMobileCenterInternal.h"
#import "MSMobileCenterPrivate.h"
#import "OCMock.h"
#import <OCHamcrestIOS/OCHamcrestIOS.h>
#import <XCTest/XCTest.h>
#import "MSServiceInternal.h"
static NSString *const kSMInstallIdStringExample = @"F18499DA-5C3D-4F05-B4E8-D8C9C06A6F09";
@ -139,4 +141,24 @@ static NSString *const kSMNullifiedInstallIdString = @"00000000-0000-0000-0000-0
[MSMobileCenter configureWithAppSecret:@"App-Secret"];
XCTAssertTrue([MSMobileCenter isConfigured]);
}
- (void)testSortingServicesWorks {
// If
id<MSServiceCommon> mockServiceMaxPrio = OCMProtocolMock(@protocol(MSServiceCommon));
OCMStub([mockServiceMaxPrio sharedInstance]).andReturn(mockServiceMaxPrio);
OCMStub([mockServiceMaxPrio initializationPriority]).andReturn(MSInitializationPriorityMax);
id<MSServiceCommon> mockServiceDefaultPrio = OCMProtocolMock(@protocol(MSServiceCommon));
OCMStub([mockServiceDefaultPrio sharedInstance]).andReturn(mockServiceDefaultPrio);
OCMStub([mockServiceDefaultPrio initializationPriority]).andReturn(MSInitializationPriorityDefault);
// When
NSArray<MSServiceAbstract *> *sorted = [self.sut sortServices:@[mockServiceDefaultPrio, mockServiceMaxPrio]];
// Then
XCTAssertTrue([sorted[0] initializationPriority] == MSInitializationPriorityMax);
XCTAssertTrue([sorted[1] initializationPriority] == MSInitializationPriorityDefault);
}
@end

Просмотреть файл

@ -37,6 +37,10 @@
return MSPriorityDefault;
}
- (MSInitializationPriority)initializationPriority {
return MSInitializationPriorityDefault;
}
+ (NSString *)logTag {
return @"MSServiceAbstractTest";
}
@ -319,4 +323,8 @@
OCMVerify([logManagerMock setEnabled:YES andDeleteDataOnDisabled:YES forPriority:self.abstractService.priority]);
}
- (void)testInitializationPriorityCorrect {
XCTAssertTrue([self.abstractService initializationPriority] == MSInitializationPriorityDefault);
}
@end

Просмотреть файл

@ -71,6 +71,10 @@ static dispatch_once_t onceToken;
return MSPriorityDefault;
}
- (MSInitializationPriority)initializationPriority {
return MSInitializationPriorityDefault;
}
#pragma mark - MSServiceAbstract
- (void)applyEnabledState:(BOOL)isEnabled {

Просмотреть файл

@ -268,4 +268,8 @@ static NSString *const kMSTestAppSecret = @"TestAppSecret";
self.didFailSendingEventLogWasCalled = true;
}
- (void)testInitializationPriorityCorrect {
XCTAssertTrue([[MSAnalytics sharedInstance] initializationPriority] == MSInitializationPriorityDefault);
}
@end

Просмотреть файл

@ -272,6 +272,10 @@ static void uncaught_cxx_exception_handler(const MSCrashesUncaughtCXXExceptionIn
return MSPriorityHigh;
}
- (MSInitializationPriority)initializationPriority {
return MSInitializationPriorityMax;
}
#pragma mark - MSLogManagerDelegate
/**
@ -506,17 +510,18 @@ static void uncaught_cxx_exception_handler(const MSCrashesUncaughtCXXExceptionIn
if ([[tmp pathExtension] isEqualToString:kMSLogBufferFileExtension]) {
NSString *filePath = [self.logBufferDir stringByAppendingPathComponent:tmp];
NSData *serializedLog = [NSData dataWithContentsOfFile:filePath];
id <MSLog> item = [NSKeyedUnarchiver unarchiveObjectWithData:serializedLog];
if (item) {
if ([((NSObject *) item) isKindOfClass:[MSAppleErrorLog class]]) {
[self.logManager processLog:item withPriority:self.priority];
} else {
[self.logManager processLog:item withPriority:MSPriorityDefault];
if(serializedLog && serializedLog.length && serializedLog.length > 0) {
id <MSLog> item = [NSKeyedUnarchiver unarchiveObjectWithData:serializedLog];
if (item) {
if ([((NSObject *) item) isKindOfClass:[MSAppleErrorLog class]]) {
[self.logManager processLog:item withPriority:self.priority];
} else {
[self.logManager processLog:item withPriority:MSPriorityDefault];
}
}
// Create empty new file, overwrites the old one.
[[NSFileManager defaultManager] createFileAtPath:filePath contents:[NSData data] attributes:nil];
}
// Create empty new file, overwrites the old one.
[[NSFileManager defaultManager] createFileAtPath:filePath contents:[NSData data] attributes:nil];
}
}
}

Просмотреть файл

@ -222,4 +222,8 @@ static NSString *const kMSTestAppSecret = @"TestAppSecret";
XCTAssertTrue(self.sut.bufferIndex == 1);
}
- (void)testInitializationPriorityCorrect {
XCTAssertTrue([[MSCrashes sharedInstance] initializationPriority] == MSInitializationPriorityMax);
}
@end