diff --git a/calabash/Classes/FranklyServer/Routes/LPVersionRoute.h b/calabash/Classes/FranklyServer/Routes/LPVersionRoute.h index 262833aca..b3b6d0574 100644 --- a/calabash/Classes/FranklyServer/Routes/LPVersionRoute.h +++ b/calabash/Classes/FranklyServer/Routes/LPVersionRoute.h @@ -21,7 +21,7 @@ Do not change the 'CALABASH VERSION' portion of the following constant without updating the ruby API. ******************/ -#define kLPCALABASHVERSION @"CALABASH VERSION: 0.11.3" +#define kLPCALABASHVERSION @"CALABASH VERSION: 0.11.4.pre1" @interface LPVersionRoute : NSObject diff --git a/calabash/Classes/Utils/LPUIAUserPrefsChannel.m b/calabash/Classes/Utils/LPUIAUserPrefsChannel.m index 366a6c717..bb1e726be 100644 --- a/calabash/Classes/Utils/LPUIAUserPrefsChannel.m +++ b/calabash/Classes/Utils/LPUIAUserPrefsChannel.m @@ -27,13 +27,12 @@ #import "LPUIAUserPrefsChannel.h" -#define MAX_LOOP_COUNT 1200 - const static NSString *LPUIAChannelUIAPrefsRequestKey = @"__calabashRequest"; const static NSString *LPUIAChannelUIAPrefsResponseKey = @"__calabashResponse"; const static NSString *LPUIAChannelUIAPrefsIndexKey = @"index"; const static NSString *LPUIAChannelUIAPrefsCommandKey = @"command"; const static NSTimeInterval LPUIAChannelUIADelay = 0.1; +const static NSInteger LPUIAChannelMaximumLoopCount = 1200; @implementation LPUIAUserPrefsChannel { dispatch_queue_t _uiaQueue; @@ -59,11 +58,9 @@ - (id) init { return self; } - -// todo LPUIAChannel.m [super dealloc] should be called _last_ - (void) dealloc { - [super dealloc]; dispatch_release(_uiaQueue); + [super dealloc]; } @@ -78,15 +75,22 @@ - (void) runAutomationCommand:(NSString *) command then:(void (^)(NSDictionary * dispatch_async(_uiaQueue, ^{ [self requestExecutionOf:command]; + NSLog(@"requested execution of command: %@", command); NSDictionary *result = nil; NSUInteger loopCount = 0; while (1) {//Loop waiting for response + [[NSUserDefaults standardUserDefaults] synchronize]; NSDictionary *resultPrefs = [self userPreferences]; NSDictionary *currentResponse = [resultPrefs objectForKey:LPUIAChannelUIAPrefsResponseKey]; + NSLog(@"Current request: %@", [resultPrefs objectForKey:LPUIAChannelUIAPrefsRequestKey]); + if (currentResponse) { NSUInteger responseIndex = [(NSNumber *) [currentResponse objectForKey:LPUIAChannelUIAPrefsIndexKey] unsignedIntegerValue]; + NSLog(@"Current response: %@", currentResponse); + NSLog(@"Server current index: %lu",(unsigned long) _scriptIndex); + NSLog(@"response current index: %lu",(unsigned long) responseIndex); if (responseIndex == _scriptIndex) { result = currentResponse; break; @@ -94,7 +98,7 @@ - (void) runAutomationCommand:(NSString *) command then:(void (^)(NSDictionary * } [NSThread sleepForTimeInterval:LPUIAChannelUIADelay]; loopCount++; - if (loopCount >= MAX_LOOP_COUNT) { + if (loopCount >= LPUIAChannelMaximumLoopCount) { NSLog(@"Timed out running command %@", command); NSLog(@"Server current index: %lu",(unsigned long) _scriptIndex); NSDictionary *prefs = [self userPreferences]; @@ -112,7 +116,6 @@ - (void) runAutomationCommand:(NSString *) command then:(void (^)(NSDictionary * }); } - - (void) requestExecutionOf:(NSString *) command { #if TARGET_IPHONE_SIMULATOR [self simulatorRequestExecutionOf:command]; @@ -121,7 +124,6 @@ - (void) requestExecutionOf:(NSString *) command { #endif } - - (NSDictionary *) userPreferences { NSDictionary *prefs = nil; #if TARGET_IPHONE_SIMULATOR @@ -134,24 +136,66 @@ - (NSDictionary *) userPreferences { return prefs; } - #if TARGET_IPHONE_SIMULATOR -(void)simulatorRequestExecutionOf:(NSString *)command { - NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:[self simulatorPreferencesPath]]; - if (!prefs) { - prefs = [NSMutableDictionary dictionary]; - } - NSDictionary *uiaRequest = [self requestForCommand:command]; + // In Xcode 6.1 and iOS 8.1, there is synchronization problem between IO + // performed by NSUserDefaults and the UIAutomation preferences API. The + // if condition detects iOS 8.1 which is a proxy for Xcode 6.1 detection. + // When Xcode 6.1 and iOS 8.1; compensate for the synchronization problem. + // Earlier iOS versions in Xcode 6.1 do not suffer from the sync problem + // because NSUserDefaults and UIAutomation preferences API do IO on different + // files. (>_>) + NSString *preferencesPlist = [self simulatorPreferencesPath]; + NSMutableDictionary *preferences; + NSString *systemVersion = [[UIDevice currentDevice] systemVersion]; + if ([systemVersion compare:@"8.1" options:NSNumericSearch] != NSOrderedAscending) { + NSLog(@"iOS >= 8.1 detected; assuming Xcode >= 6.1"); + NSInteger i = 0; + while (i < LPUIAChannelMaximumLoopCount) { + [[NSUserDefaults standardUserDefaults] synchronize]; + preferences = [NSMutableDictionary dictionaryWithContentsOfFile:preferencesPlist]; + if (!preferences) { + preferences = [NSMutableDictionary dictionary]; + NSLog(@"Empty preferences... resetting"); + } + + NSDictionary *uiaRequest = [self requestForCommand:command]; + [preferences setObject:uiaRequest forKey:LPUIAChannelUIAPrefsRequestKey]; + BOOL writeSuccess = [preferences writeToFile:preferencesPlist + atomically:YES]; - [prefs setObject:uiaRequest forKey:LPUIAChannelUIAPrefsRequestKey]; - [prefs writeToFile:[self simulatorPreferencesPath] atomically:YES]; + if (!writeSuccess) { + NSLog(@"Preparing for retry of simulatorRequestExecutionOf:"); + } + + if ([self validateRequestWritten:uiaRequest]) { + return; + } else { + i++; + NSLog(@"Validation of request failed... Retrying - %@ of %@", + @(i), @(LPUIAChannelMaximumLoopCount)); + [NSThread sleepForTimeInterval:LPUIAChannelUIADelay]; + } + } + } else { + NSLog(@"iOS < 8.1 detected; assuming Xcode < 6.1"); + preferences = [NSMutableDictionary dictionaryWithContentsOfFile:preferencesPlist]; + + if (!preferences) { + preferences = [NSMutableDictionary dictionary]; + NSLog(@"Empty preferences... resetting"); + } + NSDictionary *uiaRequest = [self requestForCommand:command]; + + [preferences setObject:uiaRequest forKey:LPUIAChannelUIAPrefsRequestKey]; + [preferences writeToFile:preferencesPlist atomically:YES]; + } } #endif // TARGET_IPHONE_SIMULATOR - - (void) deviceRequestExecutionOf:(NSString *) command { NSInteger i=0; - while (i