/core/externals/update-engine/externals/google-toolbox-for-mac/Foundation/GTMAbstractDOListenerTest.m

http://macfuse.googlecode.com/ · 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. #import "GTMSenTestCase.h"
  19. #import "GTMAbstractDOListener.h"
  20. // Needed for GTMUnitTestDevLog expectPattern
  21. #import "GTMUnitTestDevLog.h"
  22. // Used for request/reply timeouts
  23. #define kDefaultTimeout 0.5
  24. // Used when waiting for something to shutdown
  25. #define kDelayTimeout 30.0
  26. enum {
  27. kGTMAbstractDOConditionWaiting = 123,
  28. kGTMAbstractDOConditionReceivedMessage
  29. };
  30. #pragma mark -
  31. #pragma mark Test Protocols
  32. @protocol TestServerDOProtocol
  33. - (oneway void)testCommand;
  34. - (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay;
  35. @end
  36. @protocol TestServerEvilDOProtocol
  37. // This command is not implemented, but is declared to remove all compiler
  38. // warnings.
  39. //
  40. - (oneway void)evilCommand;
  41. @end
  42. @protocol TestServerDelegateProtocol
  43. - (void)clientSentMessage;
  44. @end
  45. #pragma mark -
  46. #pragma mark Test Server
  47. @interface TestServer : GTMAbstractDOListener<TestServerDOProtocol> {
  48. @private
  49. __weak id delegate_;
  50. }
  51. - (void)setDelegate:(id)delegate;
  52. @end
  53. @implementation TestServer
  54. - (void)setDelegate:(id)delegate {
  55. delegate_ = delegate;
  56. }
  57. - (in bycopy NSNumber *)delayResponseForTime:(in byref NSNumber *)delay {
  58. NSDate *future = [NSDate dateWithTimeIntervalSinceNow:[delay doubleValue]];
  59. [NSThread sleepUntilDate:future];
  60. return [NSNumber numberWithDouble:kDefaultTimeout];
  61. }
  62. - (oneway void)testCommand {
  63. [delegate_ performSelector:@selector(clientSentMessage)];
  64. }
  65. @end
  66. #pragma mark -
  67. #pragma mark Test Client
  68. @interface TestClient : NSObject {
  69. @private
  70. id proxy_;
  71. NSString *serverName_;
  72. }
  73. - (id)initWithName:(NSString *)name;
  74. - (id)connect;
  75. - (void)disconnect;
  76. @end
  77. @implementation TestClient
  78. - (id)initWithName:(NSString *)name {
  79. self = [super init];
  80. if (self) {
  81. serverName_ = [[NSString alloc] initWithString:name];
  82. if (!serverName_) {
  83. [self release];
  84. self = nil;
  85. }
  86. }
  87. return self;
  88. }
  89. - (void)finalize {
  90. [self disconnect];
  91. [super finalize];
  92. }
  93. - (void)dealloc {
  94. [self disconnect];
  95. [serverName_ release];
  96. [super dealloc];
  97. }
  98. - (id)connect {
  99. NSConnection *connection =
  100. [NSConnection connectionWithRegisteredName:serverName_ host:nil];
  101. [connection setReplyTimeout:kDefaultTimeout];
  102. [connection setRequestTimeout:kDefaultTimeout];
  103. @try {
  104. proxy_ = [[connection rootProxy] retain];
  105. } @catch (NSException *e) {
  106. [self disconnect];
  107. }
  108. return proxy_;
  109. }
  110. - (void)disconnect {
  111. NSConnection *connection =
  112. [NSConnection connectionWithRegisteredName:serverName_ host:nil];
  113. [connection invalidate];
  114. [proxy_ release];
  115. proxy_ = nil;
  116. }
  117. @end
  118. #pragma mark -
  119. #pragma mark Tests
  120. @interface GTMAbstractDOListenerTest : GTMTestCase<TestServerDelegateProtocol> {
  121. @private
  122. NSConditionLock *lock_;
  123. }
  124. @end
  125. @implementation GTMAbstractDOListenerTest
  126. - (void)clientSentMessage {
  127. NSDate *future = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout];
  128. STAssertTrue([lock_ lockWhenCondition:kGTMAbstractDOConditionWaiting
  129. beforeDate:future], @"Unable to acquire lock "
  130. @"for client send message. This is BAD!");
  131. [lock_ unlockWithCondition:kGTMAbstractDOConditionReceivedMessage];
  132. }
  133. - (void)listenerErrorEncountered:(id)error {
  134. // Do nothing
  135. }
  136. - (void)testAbstractDOListenerProtocol {
  137. lock_ =
  138. [[NSConditionLock alloc] initWithCondition:kGTMAbstractDOConditionWaiting];
  139. [lock_ autorelease];
  140. NSString *serverName = @"ProtoTest";
  141. // Build and start the server
  142. TestServer *listener =
  143. [[TestServer alloc] initWithRegisteredName:serverName
  144. protocol:@protocol(TestServerDOProtocol)];
  145. [listener autorelease];
  146. [listener setDelegate:self];
  147. [GTMUnitTestDevLog expectPattern:@"listening on.*"];
  148. [listener runInCurrentThread];
  149. // Connect with our simple client
  150. TestClient *client =
  151. [[[TestClient alloc] initWithName:serverName] autorelease];
  152. id proxy = [client connect];
  153. STAssertNotNil(proxy, @"should have a proxy object");
  154. [proxy testCommand];
  155. NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout];
  156. while (![lock_ tryLockWhenCondition:kGTMAbstractDOConditionReceivedMessage] &&
  157. ([timeout compare:[NSDate date]] == NSOrderedDescending)) {
  158. NSDate* runUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
  159. [[NSRunLoop currentRunLoop] runUntilDate:runUntil];
  160. }
  161. STAssertFalse([lock_ tryLockWhenCondition:kGTMAbstractDOConditionWaiting],
  162. @"A message was never received from the client.");
  163. STAssertThrows([proxy evilCommand],
  164. @"An exception should have been thrown for a method not in"
  165. @"the specified protocol.");
  166. [client disconnect];
  167. [listener shutdown];
  168. STAssertNil([listener connection], @"The connection should be nil after "
  169. @"shutdown.");
  170. // We are done with the lock.
  171. [lock_ unlockWithCondition:kGTMAbstractDOConditionWaiting];
  172. }
  173. - (void)testAbstractDOListenerBadInitializers {
  174. [GTMUnitTestDevLog expectString:
  175. @"Failed to create a listener, a protocol must be specified"];
  176. [GTMUnitTestDevLog expectString:
  177. @"Failed to create a listener, a name must be specified"];
  178. TestServer *listener = [[TestServer alloc] init];
  179. STAssertNil(listener, @"We should not have created a server using init");
  180. [GTMUnitTestDevLog expectString:
  181. @"Failed to create a listener, a name must be specified"];
  182. listener =
  183. [[TestServer alloc] initWithRegisteredName:nil
  184. protocol:@protocol(TestServerDOProtocol)
  185. port:[NSMachPort port]];
  186. STAssertNil(listener, @"We should not have created a server with a nil name");
  187. [GTMUnitTestDevLog expectString:
  188. @"Failed to create a listener, a protocol must be specified"];
  189. listener =
  190. [[TestServer alloc] initWithRegisteredName:@"NilProtocol"
  191. protocol:nil
  192. port:[NSMachPort port]];
  193. STAssertNil(listener,
  194. @"We should not have created a server with a nil protocol");
  195. [GTMUnitTestDevLog expectString:
  196. @"Failed to create a listener, a port must be specified"];
  197. listener =
  198. [[TestServer alloc] initWithRegisteredName:@"NilPort"
  199. protocol:@protocol(TestServerDOProtocol)
  200. port:nil];
  201. STAssertNil(listener, @"We should not have created a server with a nil port");
  202. }
  203. - (void)testAbstractDOListenerMultipleRegistration {
  204. TestServer *listener =
  205. [[[TestServer alloc] initWithRegisteredName:@"MyUniqueName"
  206. protocol:@protocol(TestServerDOProtocol)
  207. port:[NSMachPort port]] autorelease];
  208. [GTMUnitTestDevLog expectPattern:@"listening on.*"];
  209. [listener runInCurrentThread];
  210. TestServer *copyCat =
  211. [[[TestServer alloc] initWithRegisteredName:@"copyCat"
  212. protocol:@protocol(TestServerDOProtocol)
  213. port:[NSMachPort port]] autorelease];
  214. STAssertTrue(([[copyCat registeredName] isEqualToString:@"copyCat"]),
  215. @"The name we set to register with is not correct.");
  216. TestServer *listener2 =
  217. [[[TestServer alloc] initWithRegisteredName:@"MyUniqueName"
  218. protocol:@protocol(TestServerDOProtocol)
  219. port:[NSMachPort port]] autorelease];
  220. [GTMUnitTestDevLog expectPattern:@"failed to register.*"];
  221. [listener2 runInCurrentThread];
  222. STAssertNil([listener2 connection], @"We should not have been able to create "
  223. @"a server with a name that has already been taken.");
  224. }
  225. - (void)testAbstractDOListenerRequestTimeout {
  226. NSString *serverName = @"RequestTimeoutTest";
  227. // Build and start the server
  228. TestServer *listener =
  229. [[TestServer alloc] initWithRegisteredName:serverName
  230. protocol:@protocol(TestServerDOProtocol)];
  231. [listener autorelease];
  232. [listener setReplyTimeout:kDefaultTimeout];
  233. [listener setRequestTimeout:kDefaultTimeout];
  234. STAssertLessThanOrEqual(ABS([listener replyTimeout] - kDefaultTimeout),
  235. (kDefaultTimeout / pow(kDefaultTimeout, 15)), nil);
  236. STAssertLessThanOrEqual(ABS([listener requestTimeout] - kDefaultTimeout),
  237. (kDefaultTimeout / pow(kDefaultTimeout, 15)), nil);
  238. NSTimeInterval customHeartRate = 0.25;
  239. [listener setThreadHeartRate:0.25];
  240. STAssertLessThanOrEqual(ABS([listener ThreadHeartRate] - customHeartRate),
  241. (customHeartRate / pow(customHeartRate, 15)), nil);
  242. [GTMUnitTestDevLog expectPattern:@"listening on.*"];
  243. [listener runInNewThreadWithErrorTarget:self
  244. selector:@selector(listenerErrorEncountered:)
  245. withObjectArgument:nil];
  246. // It will take a little while for the new thread to spin up and start
  247. // listening. We will spin here and wait for it to come on-line.
  248. NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout];
  249. while (![listener connection] &&
  250. ([timeout compare:[NSDate date]] == NSOrderedDescending)) {
  251. NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05];
  252. [[NSRunLoop currentRunLoop] runUntilDate:waitTime];
  253. }
  254. STAssertNotNil([listener connection],
  255. @"The server never created a connection.");
  256. // Connect with our simple client
  257. TestClient *client =
  258. [[[TestClient alloc] initWithName:serverName] autorelease];
  259. id proxy = [client connect];
  260. STAssertNotNil(proxy, @"should have a proxy object");
  261. NSNumber *overDelay = [NSNumber numberWithDouble:(kDefaultTimeout + 0.25)];
  262. STAssertThrows([proxy delayResponseForTime:overDelay],
  263. @"An exception should have been thrown for the response taking"
  264. @"longer than the replyTimout.");
  265. [client disconnect];
  266. [listener shutdown];
  267. timeout = [NSDate dateWithTimeIntervalSinceNow:kDelayTimeout];
  268. while ([listener connection] &&
  269. ([timeout compare:[NSDate date]] == NSOrderedDescending)) {
  270. NSDate *waitTime = [NSDate dateWithTimeIntervalSinceNow:0.05];
  271. [[NSRunLoop currentRunLoop] runUntilDate:waitTime];
  272. }
  273. STAssertNil([listener connection],
  274. @"The connection should be nil after shutdown.");
  275. }
  276. - (void)testAbstractDOListenerRelease {
  277. NSUInteger listenerCount = [[GTMAbstractDOListener allListeners] count];
  278. GTMAbstractDOListener *listener =
  279. [[GTMAbstractDOListener alloc] initWithRegisteredName:@"FOO"
  280. protocol:@protocol(NSObject)
  281. port:[NSPort port]];
  282. STAssertNotNil(listener, nil);
  283. // We throw an autorelease pool here because allStores does a couple of
  284. // autoreleased retains on us which would screws up our retain count
  285. // numbers.
  286. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  287. STAssertEquals([[GTMAbstractDOListener allListeners] count],
  288. listenerCount + 1, nil);
  289. [pool drain];
  290. STAssertEquals([listener retainCount], (NSUInteger)1, nil);
  291. [listener release];
  292. STAssertEquals([[GTMAbstractDOListener allListeners] count], listenerCount,
  293. nil);
  294. }
  295. @end