Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stability uia timeout/lost write/read #89

Merged
merged 6 commits into from
Nov 4, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion calabash/Classes/FranklyServer/Routes/LPVersionRoute.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <LPRoute>

Expand Down
83 changes: 64 additions & 19 deletions calabash/Classes/Utils/LPUIAUserPrefsChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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];
}


Expand All @@ -78,23 +75,30 @@ - (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;
}
}
[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];
Expand All @@ -112,7 +116,6 @@ - (void) runAutomationCommand:(NSString *) command then:(void (^)(NSDictionary *
});
}


- (void) requestExecutionOf:(NSString *) command {
#if TARGET_IPHONE_SIMULATOR
[self simulatorRequestExecutionOf:command];
Expand All @@ -121,7 +124,6 @@ - (void) requestExecutionOf:(NSString *) command {
#endif
}


- (NSDictionary *) userPreferences {
NSDictionary *prefs = nil;
#if TARGET_IPHONE_SIMULATOR
Expand All @@ -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<MAX_LOOP_COUNT) {
while (i<LPUIAChannelMaximumLoopCount) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *uiaRequest = [self requestForCommand:command];

Expand All @@ -171,7 +215,8 @@ - (void) deviceRequestExecutionOf:(NSString *) command {
}

-(BOOL)validateRequestWritten:(NSDictionary*)uiaRequest {
NSDictionary *defaults = [self userPreferences];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
NSDictionary *written = [defaults objectForKey:(NSString*)LPUIAChannelUIAPrefsRequestKey];
if (!written) {
return NO;
Expand Down