aboutsummaryrefslogtreecommitdiff
path: root/Foundation
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-03-31 22:00:24 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-03-31 22:00:24 +0000
commit78625ee9d7bd994dd2ce78b76b7282444c181a83 (patch)
treeaf3cf807e70099ab86ee1877ca851133431a0813 /Foundation
parentc9fa45bd094b6ac4aa0a71db84e23ee65198ad39 (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.h8
-rw-r--r--Foundation/GTMAbstractDOListener.m12
-rw-r--r--Foundation/GTMAbstractDOListenerTest.m238
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 =