diff options
author | 2009-03-31 22:00:24 +0000 | |
---|---|---|
committer | 2009-03-31 22:00:24 +0000 | |
commit | 78625ee9d7bd994dd2ce78b76b7282444c181a83 (patch) | |
tree | af3cf807e70099ab86ee1877ca851133431a0813 /Foundation | |
parent | c9fa45bd094b6ac4aa0a71db84e23ee65198ad39 (diff) |
[Author: krisr]
Increase test coverage
DELTA=246 (241 added, 0 deleted, 5 changed)
R=thomasvl,dmaclach
Diffstat (limited to 'Foundation')
-rw-r--r-- | Foundation/GTMAbstractDOListener.h | 8 | ||||
-rw-r--r-- | Foundation/GTMAbstractDOListener.m | 12 | ||||
-rw-r--r-- | Foundation/GTMAbstractDOListenerTest.m | 238 |
3 files changed, 254 insertions, 4 deletions
diff --git a/Foundation/GTMAbstractDOListener.h b/Foundation/GTMAbstractDOListener.h index e865727..77eb111 100644 --- a/Foundation/GTMAbstractDOListener.h +++ b/Foundation/GTMAbstractDOListener.h @@ -41,6 +41,7 @@ NSTimeInterval requestTimeout_; NSTimeInterval replyTimeout_; NSPort *port_; + NSTimeInterval heartRate_; #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 GTMReceivePortDelegate *receivePortDelegate_; // Strong (only used on Tiger) @@ -108,6 +109,13 @@ - (NSTimeInterval)replyTimeout; - (void)setReplyTimeout:(NSTimeInterval)timeout; +// Get/set how long the thread will spin the run loop. This only takes affect +// if runInNewThreadWithErrorTarget:selector:withObjectArgument: is used. The +// default heart rate is 10.0 seconds. +// +- (void)setThreadHeartRate:(NSTimeInterval)heartRate; +- (NSTimeInterval)ThreadHeartRate; + // Returns the listeners associated NSConnection. May be nil if no connection // has been setup yet. // diff --git a/Foundation/GTMAbstractDOListener.m b/Foundation/GTMAbstractDOListener.m index 772960b..ec88749 100644 --- a/Foundation/GTMAbstractDOListener.m +++ b/Foundation/GTMAbstractDOListener.m @@ -120,6 +120,8 @@ static NSMutableSet *gAllListeners = nil; requestTimeout_ = -1; replyTimeout_ = -1; + heartRate_ = (NSTimeInterval)10.0; + _GTMDevAssert(gAllListeners, @"gAllListeners is not nil"); @synchronized (gAllListeners) { [gAllListeners addObject:self]; @@ -175,6 +177,14 @@ static NSMutableSet *gAllListeners = nil; replyTimeout_ = timeout; } +- (void)setThreadHeartRate:(NSTimeInterval)heartRate { + heartRate_ = heartRate; +} + +- (NSTimeInterval)ThreadHeartRate { + return heartRate_; +} + - (NSConnection *)connection { return connection_; } @@ -370,7 +380,7 @@ static NSMutableSet *gAllListeners = nil; NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; // Wrap our runloop in case we get an exception from DO @try { - NSDate *waitDate = [NSDate dateWithTimeIntervalSinceNow:10]; + NSDate *waitDate = [NSDate dateWithTimeIntervalSinceNow:heartRate_]; [[NSRunLoop currentRunLoop] runUntilDate:waitDate]; } @catch (id e) { _GTMDevLog(@"Listener '%@' caught exception: %@", registeredName_, e); diff --git a/Foundation/GTMAbstractDOListenerTest.m b/Foundation/GTMAbstractDOListenerTest.m index 6076724..b420240 100644 --- a/Foundation/GTMAbstractDOListenerTest.m +++ b/Foundation/GTMAbstractDOListenerTest.m @@ -22,14 +22,246 @@ // Needed for GTMIsGarbageCollectionEnabled #import "GTMGarbageCollection.h" -@interface GTMAbstractDOListenerTest : GTMTestCase +// Needed for GTMUnitTestDevLog expectPattern +#import "GTMUnitTestDevLog.h" + +// Used for request/reply timeouts +#define kDefaultTimeout 0.5 + +// Used when waiting for something to shutdown +#define kDelayTimeout 30.0 + +enum { + kGTMAbstractDOConditionWaiting = 123, + kGTMAbstractDOConditionReceivedMessage +}; + +#pragma mark - +#pragma mark Test Protocols + +@protocol TestServerDOProtocol +- (oneway void)testCommand; +- (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay; +@end + +@protocol TestServerEvilDOProtocol +// This command is not implemented, but is declared to remove all compiler +// warnings. +// +- (oneway void)evilCommand; +@end + +@protocol TestServerDelegateProtocol +- (void)clientSentMessage; @end -// TODO: we need to add more tests for this class. Examples: send messages and -// send messages that are in the protocol. +#pragma mark - +#pragma mark Test Server + +@interface TestServer : GTMAbstractDOListener<TestServerDOProtocol> { + @private + __weak id delegate_; +} +- (void)setDelegate:(id)delegate; +@end + +@implementation TestServer + +- (void)setDelegate:(id)delegate { + delegate_ = delegate; +} + +- (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay { + NSDate *future = [NSDate dateWithTimeIntervalSinceNow:[delay doubleValue]]; + [NSThread sleepUntilDate:future]; + return [NSNumber numberWithDouble:kDefaultTimeout]; +} + +- (oneway void)testCommand { + [delegate_ performSelector:@selector(clientSentMessage)]; +} + +@end + +#pragma mark - +#pragma mark Test Client + +@interface TestClient : NSObject { + @private + id proxy_; + NSString *serverName_; +} +- (id)initWithName:(NSString *)name; +- (id)connect; +- (void)disconnect; +@end + +@implementation TestClient +- (id)initWithName:(NSString *)name { + serverName_ = [[NSString alloc] initWithString:name]; + if (!serverName_) { + [self release]; + self = nil; + } + return self; +} + +- (void)finalize { + [self disconnect]; + [super finalize]; +} + +- (void)dealloc { + [self disconnect]; + [serverName_ release]; + [super dealloc]; +} + +- (id)connect { + NSConnection *connection = + [NSConnection connectionWithRegisteredName:serverName_ host:nil]; + + [connection setReplyTimeout:kDefaultTimeout]; + [connection setRequestTimeout:kDefaultTimeout]; + + @try { + proxy_ = [[connection rootProxy] retain]; + } @catch (NSException *e) { + [self disconnect]; + } + return proxy_; +} + +- (void)disconnect { + NSConnection *connection = + [NSConnection connectionWithRegisteredName:serverName_ host:nil]; + [connection invalidate]; + [proxy_ release]; + proxy_ = nil; +} + +@end + +#pragma mark - +#pragma mark Tests + +@interface GTMAbstractDOListenerTest : GTMTestCase<TestServerDelegateProtocol> { + @private + NSConditionLock *lock_; +} +@end @implementation GTMAbstractDOListenerTest +- (void)clientSentMessage { + NSDate *future = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout]; + STAssertTrue([lock_ lockWhenCondition:kGTMAbstractDOConditionWaiting + beforeDate:future], @"Unable to acquire lock " + @"for client send message. This is BAD!"); + [lock_ unlockWithCondition:kGTMAbstractDOConditionReceivedMessage]; +} + +- (void)testAbstractDOListenerProtocol { + lock_ = + [[NSConditionLock alloc] initWithCondition:kGTMAbstractDOConditionWaiting]; + [lock_ autorelease]; + + NSString *serverName = @"ProtoTest"; + + // Build and start the server + TestServer *listener = + [[TestServer alloc] initWithRegisteredName:serverName + protocol:@protocol(TestServerDOProtocol)]; + [listener autorelease]; + [listener setDelegate:self]; + [GTMUnitTestDevLog expectPattern:@"listening on.*"]; + [listener runInCurrentThread]; + + // Connect with our simple client + TestClient *client = + [[[TestClient alloc] initWithName:serverName] autorelease]; + id proxy = [client connect]; + STAssertNotNil(proxy, @"should have a proxy object"); + + [proxy testCommand]; + + NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; + while (![lock_ tryLockWhenCondition:kGTMAbstractDOConditionReceivedMessage] && + ([timeout compare:[NSDate date]] == NSOrderedDescending)) { + NSDate* runUntil = [NSDate dateWithTimeIntervalSinceNow:0.1]; + [[NSRunLoop currentRunLoop] runUntilDate:runUntil]; + } + + STAssertFalse([lock_ tryLockWhenCondition:kGTMAbstractDOConditionWaiting], + @"A message was never received from the client."); + + STAssertThrows([proxy evilCommand], + @"An exception should have been thrown for a method not in" + @"the specified protocol."); + + [client disconnect]; + [listener shutdown]; + + STAssertNil([listener connection], @"The connection should be nil after " + @"shutdown."); + + // We are done with the lock. + [lock_ unlockWithCondition:kGTMAbstractDOConditionWaiting]; +} + +- (void)testAbstractDOListenerRequestTimeout { + NSString *serverName = @"RequestTimeoutTest"; + + // Build and start the server + TestServer *listener = + [[TestServer alloc] initWithRegisteredName:serverName + protocol:@protocol(TestServerDOProtocol)]; + [listener autorelease]; + [listener setReplyTimeout:kDefaultTimeout]; + [listener setRequestTimeout:kDefaultTimeout]; + [listener setThreadHeartRate:0.25]; + [GTMUnitTestDevLog expectPattern:@"listening on.*"]; + [listener runInNewThreadWithErrorTarget:nil + selector:NULL + withObjectArgument:nil]; + + // It will take a little while for the new thread to spin up and start + // listening. We will spin here and wait for it to come on-line. + NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; + while (![listener connection] && + ([timeout compare:[NSDate date]] == NSOrderedDescending)) { + NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05]; + [[NSRunLoop currentRunLoop] runUntilDate:waitTime]; + } + + STAssertNotNil([listener connection], + @"The server never created a connection."); + + // Connect with our simple client + TestClient *client = + [[[TestClient alloc] initWithName:serverName] autorelease]; + id proxy = [client connect]; + STAssertNotNil(proxy, @"should have a proxy object"); + + NSNumber *overDelay = [NSNumber numberWithDouble:(kDefaultTimeout + 0.25)]; + STAssertThrows([proxy delayResponseForTime:overDelay], + @"An exception should have been thrown for the response taking" + @"longer than the replyTimout."); + + [client disconnect]; + [listener shutdown]; + + timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; + while ([listener connection] && + ([timeout compare:[NSDate date]] == NSOrderedDescending)) { + NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05]; + [[NSRunLoop currentRunLoop] runUntilDate:waitTime]; + } + + STAssertNil([listener connection], @"The connection should be nil after " + @"shutdown."); +} + - (void)testAbstractDOListenerRelease { NSUInteger listenerCount = [[GTMAbstractDOListener allListeners] count]; GTMAbstractDOListener *listener = |