/core/externals/update-engine/externals/google-toolbox-for-mac/Foundation/GTMAbstractDOListenerTest.m
Objective C | 365 lines | 261 code | 70 blank | 34 comment | 8 complexity | 8f06569075b8a794918f1bc59156d837 MD5 | raw file
1// 2// GTMAbstractDOListenerTest.m 3// 4// Copyright 2006-2009 Google Inc. 5// 6// Licensed under the Apache License, Version 2.0 (the "License"); you may not 7// use this file except in compliance with the License. You may obtain a copy 8// of the License at 9// 10// http://www.apache.org/licenses/LICENSE-2.0 11// 12// Unless required by applicable law or agreed to in writing, software 13// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15// License for the specific language governing permissions and limitations under 16// the License. 17// 18 19#import "GTMSenTestCase.h" 20#import "GTMAbstractDOListener.h" 21 22// Needed for GTMUnitTestDevLog expectPattern 23#import "GTMUnitTestDevLog.h" 24 25// Used for request/reply timeouts 26#define kDefaultTimeout 0.5 27 28// Used when waiting for something to shutdown 29#define kDelayTimeout 30.0 30 31enum { 32 kGTMAbstractDOConditionWaiting = 123, 33 kGTMAbstractDOConditionReceivedMessage 34}; 35 36#pragma mark - 37#pragma mark Test Protocols 38 39@protocol TestServerDOProtocol 40- (oneway void)testCommand; 41- (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay; 42@end 43 44@protocol TestServerEvilDOProtocol 45// This command is not implemented, but is declared to remove all compiler 46// warnings. 47// 48- (oneway void)evilCommand; 49@end 50 51@protocol TestServerDelegateProtocol 52- (void)clientSentMessage; 53@end 54 55#pragma mark - 56#pragma mark Test Server 57 58@interface TestServer : GTMAbstractDOListener<TestServerDOProtocol> { 59 @private 60 __weak id delegate_; 61} 62- (void)setDelegate:(id)delegate; 63@end 64 65@implementation TestServer 66 67- (void)setDelegate:(id)delegate { 68 delegate_ = delegate; 69} 70 71- (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay { 72 NSDate *future = [NSDate dateWithTimeIntervalSinceNow:[delay doubleValue]]; 73 [NSThread sleepUntilDate:future]; 74 return [NSNumber numberWithDouble:kDefaultTimeout]; 75} 76 77- (oneway void)testCommand { 78 [delegate_ performSelector:@selector(clientSentMessage)]; 79} 80 81@end 82 83#pragma mark - 84#pragma mark Test Client 85 86@interface TestClient : NSObject { 87 @private 88 id proxy_; 89 NSString *serverName_; 90} 91- (id)initWithName:(NSString *)name; 92- (id)connect; 93- (void)disconnect; 94@end 95 96@implementation TestClient 97- (id)initWithName:(NSString *)name { 98 self = [super init]; 99 if (self) { 100 serverName_ = [[NSString alloc] initWithString:name]; 101 if (!serverName_) { 102 [self release]; 103 self = nil; 104 } 105 } 106 return self; 107} 108 109- (void)finalize { 110 [self disconnect]; 111 [super finalize]; 112} 113 114- (void)dealloc { 115 [self disconnect]; 116 [serverName_ release]; 117 [super dealloc]; 118} 119 120- (id)connect { 121 NSConnection *connection = 122 [NSConnection connectionWithRegisteredName:serverName_ host:nil]; 123 124 [connection setReplyTimeout:kDefaultTimeout]; 125 [connection setRequestTimeout:kDefaultTimeout]; 126 127 @try { 128 proxy_ = [[connection rootProxy] retain]; 129 } @catch (NSException *e) { 130 [self disconnect]; 131 } 132 return proxy_; 133} 134 135- (void)disconnect { 136 NSConnection *connection = 137 [NSConnection connectionWithRegisteredName:serverName_ host:nil]; 138 [connection invalidate]; 139 [proxy_ release]; 140 proxy_ = nil; 141} 142 143@end 144 145#pragma mark - 146#pragma mark Tests 147 148@interface GTMAbstractDOListenerTest : GTMTestCase<TestServerDelegateProtocol> { 149 @private 150 NSConditionLock *lock_; 151} 152@end 153 154@implementation GTMAbstractDOListenerTest 155 156- (void)clientSentMessage { 157 NSDate *future = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout]; 158 STAssertTrue([lock_ lockWhenCondition:kGTMAbstractDOConditionWaiting 159 beforeDate:future], @"Unable to acquire lock " 160 @"for client send message. This is BAD!"); 161 [lock_ unlockWithCondition:kGTMAbstractDOConditionReceivedMessage]; 162} 163 164- (void)listenerErrorEncountered:(id)error { 165 // Do nothing 166} 167 168- (void)testAbstractDOListenerProtocol { 169 lock_ = 170 [[NSConditionLock alloc] initWithCondition:kGTMAbstractDOConditionWaiting]; 171 [lock_ autorelease]; 172 173 NSString *serverName = @"ProtoTest"; 174 175 // Build and start the server 176 TestServer *listener = 177 [[TestServer alloc] initWithRegisteredName:serverName 178 protocol:@protocol(TestServerDOProtocol)]; 179 [listener autorelease]; 180 [listener setDelegate:self]; 181 [GTMUnitTestDevLog expectPattern:@"listening on.*"]; 182 [listener runInCurrentThread]; 183 184 // Connect with our simple client 185 TestClient *client = 186 [[[TestClient alloc] initWithName:serverName] autorelease]; 187 id proxy = [client connect]; 188 STAssertNotNil(proxy, @"should have a proxy object"); 189 190 [proxy testCommand]; 191 192 NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; 193 while (![lock_ tryLockWhenCondition:kGTMAbstractDOConditionReceivedMessage] && 194 ([timeout compare:[NSDate date]] == NSOrderedDescending)) { 195 NSDate* runUntil = [NSDate dateWithTimeIntervalSinceNow:0.1]; 196 [[NSRunLoop currentRunLoop] runUntilDate:runUntil]; 197 } 198 199 STAssertFalse([lock_ tryLockWhenCondition:kGTMAbstractDOConditionWaiting], 200 @"A message was never received from the client."); 201 202 STAssertThrows([proxy evilCommand], 203 @"An exception should have been thrown for a method not in" 204 @"the specified protocol."); 205 206 [client disconnect]; 207 [listener shutdown]; 208 209 STAssertNil([listener connection], @"The connection should be nil after " 210 @"shutdown."); 211 212 // We are done with the lock. 213 [lock_ unlockWithCondition:kGTMAbstractDOConditionWaiting]; 214} 215 216- (void)testAbstractDOListenerBadInitializers { 217 [GTMUnitTestDevLog expectString: 218 @"Failed to create a listener, a protocol must be specified"]; 219 [GTMUnitTestDevLog expectString: 220 @"Failed to create a listener, a name must be specified"]; 221 TestServer *listener = [[TestServer alloc] init]; 222 STAssertNil(listener, @"We should not have created a server using init"); 223 224 [GTMUnitTestDevLog expectString: 225 @"Failed to create a listener, a name must be specified"]; 226 listener = 227 [[TestServer alloc] initWithRegisteredName:nil 228 protocol:@protocol(TestServerDOProtocol) 229 port:[NSMachPort port]]; 230 STAssertNil(listener, @"We should not have created a server with a nil name"); 231 232 [GTMUnitTestDevLog expectString: 233 @"Failed to create a listener, a protocol must be specified"]; 234 listener = 235 [[TestServer alloc] initWithRegisteredName:@"NilProtocol" 236 protocol:nil 237 port:[NSMachPort port]]; 238 STAssertNil(listener, 239 @"We should not have created a server with a nil protocol"); 240 241 [GTMUnitTestDevLog expectString: 242 @"Failed to create a listener, a port must be specified"]; 243 listener = 244 [[TestServer alloc] initWithRegisteredName:@"NilPort" 245 protocol:@protocol(TestServerDOProtocol) 246 port:nil]; 247 STAssertNil(listener, @"We should not have created a server with a nil port"); 248 249} 250 251- (void)testAbstractDOListenerMultipleRegistration { 252 TestServer *listener = 253 [[[TestServer alloc] initWithRegisteredName:@"MyUniqueName" 254 protocol:@protocol(TestServerDOProtocol) 255 port:[NSMachPort port]] autorelease]; 256 [GTMUnitTestDevLog expectPattern:@"listening on.*"]; 257 [listener runInCurrentThread]; 258 259 TestServer *copyCat = 260 [[[TestServer alloc] initWithRegisteredName:@"copyCat" 261 protocol:@protocol(TestServerDOProtocol) 262 port:[NSMachPort port]] autorelease]; 263 STAssertTrue(([[copyCat registeredName] isEqualToString:@"copyCat"]), 264 @"The name we set to register with is not correct."); 265 266 TestServer *listener2 = 267 [[[TestServer alloc] initWithRegisteredName:@"MyUniqueName" 268 protocol:@protocol(TestServerDOProtocol) 269 port:[NSMachPort port]] autorelease]; 270 271 [GTMUnitTestDevLog expectPattern:@"failed to register.*"]; 272 [listener2 runInCurrentThread]; 273 STAssertNil([listener2 connection], @"We should not have been able to create " 274 @"a server with a name that has already been taken."); 275} 276 277- (void)testAbstractDOListenerRequestTimeout { 278 NSString *serverName = @"RequestTimeoutTest"; 279 280 // Build and start the server 281 TestServer *listener = 282 [[TestServer alloc] initWithRegisteredName:serverName 283 protocol:@protocol(TestServerDOProtocol)]; 284 [listener autorelease]; 285 [listener setReplyTimeout:kDefaultTimeout]; 286 [listener setRequestTimeout:kDefaultTimeout]; 287 288 STAssertLessThanOrEqual(ABS([listener replyTimeout] - kDefaultTimeout), 289 (kDefaultTimeout / pow(kDefaultTimeout, 15)), nil); 290 291 STAssertLessThanOrEqual(ABS([listener requestTimeout] - kDefaultTimeout), 292 (kDefaultTimeout / pow(kDefaultTimeout, 15)), nil); 293 294 NSTimeInterval customHeartRate = 0.25; 295 [listener setThreadHeartRate:0.25]; 296 297 STAssertLessThanOrEqual(ABS([listener ThreadHeartRate] - customHeartRate), 298 (customHeartRate / pow(customHeartRate, 15)), nil); 299 300 [GTMUnitTestDevLog expectPattern:@"listening on.*"]; 301 [listener runInNewThreadWithErrorTarget:self 302 selector:@selector(listenerErrorEncountered:) 303 withObjectArgument:nil]; 304 305 // It will take a little while for the new thread to spin up and start 306 // listening. We will spin here and wait for it to come on-line. 307 NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; 308 while (![listener connection] && 309 ([timeout compare:[NSDate date]] == NSOrderedDescending)) { 310 NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05]; 311 [[NSRunLoop currentRunLoop] runUntilDate:waitTime]; 312 } 313 314 STAssertNotNil([listener connection], 315 @"The server never created a connection."); 316 317 // Connect with our simple client 318 TestClient *client = 319 [[[TestClient alloc] initWithName:serverName] autorelease]; 320 id proxy = [client connect]; 321 STAssertNotNil(proxy, @"should have a proxy object"); 322 323 NSNumber *overDelay = [NSNumber numberWithDouble:(kDefaultTimeout + 0.25)]; 324 STAssertThrows([proxy delayResponseForTime:overDelay], 325 @"An exception should have been thrown for the response taking" 326 @"longer than the replyTimout."); 327 328 [client disconnect]; 329 [listener shutdown]; 330 331 timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout]; 332 while ([listener connection] && 333 ([timeout compare:[NSDate date]] == NSOrderedDescending)) { 334 NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05]; 335 [[NSRunLoop currentRunLoop] runUntilDate:waitTime]; 336 } 337 338 STAssertNil([listener connection], 339 @"The connection should be nil after shutdown."); 340} 341 342- (void)testAbstractDOListenerRelease { 343 NSUInteger listenerCount = [[GTMAbstractDOListener allListeners] count]; 344 GTMAbstractDOListener *listener = 345 [[GTMAbstractDOListener alloc] initWithRegisteredName:@"FOO" 346 protocol:@protocol(NSObject) 347 port:[NSPort port]]; 348 STAssertNotNil(listener, nil); 349 350 // We throw an autorelease pool here because allStores does a couple of 351 // autoreleased retains on us which would screws up our retain count 352 // numbers. 353 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 354 STAssertEquals([[GTMAbstractDOListener allListeners] count], 355 listenerCount + 1, nil); 356 [pool drain]; 357 358 STAssertEquals([listener retainCount], (NSUInteger)1, nil); 359 360 [listener release]; 361 STAssertEquals([[GTMAbstractDOListener allListeners] count], listenerCount, 362 nil); 363} 364 365@end