/core/externals/google-toolbox-for-mac/Foundation/GTMTransientRootProxyTest.m

http://macfuse.googlecode.com/ · Objective C · 231 lines · 166 code · 29 blank · 36 comment · 3 complexity · c63a621ce6ec35a954900cb9e7fde635 MD5 · raw file

  1. //
  2. // GMTransientRootProxyTest.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 "GTMTransientRootProxy.h"
  20. #import "GTMUnitTestDevLog.h"
  21. #define kDefaultTimeout 5.0
  22. // === Start off declaring some auxillary data structures ===
  23. static NSString *const kTestServerName = @"gtm_test_server";
  24. static NSString *const kGTMTransientRootNameKey = @"GTMTransientRootNameKey";
  25. static NSString *const kGTMTransientRootLockKey = @"GTMTransientRootLockKey";
  26. enum {
  27. kGTMTransientThreadConditionStarting = 777,
  28. kGTMTransientThreadConditionStarted,
  29. kGTMTransientThreadConditionQuitting,
  30. kGTMTransientThreadConditionQuitted
  31. };
  32. // The @protocol that we'll use for testing with.
  33. @protocol DOTestProtocol
  34. - (oneway void)doOneWayVoid;
  35. - (bycopy NSString *)doReturnStringBycopy;
  36. - (void)throwException;
  37. @end
  38. // The "server" we'll use to test the DO connection. This server will implement
  39. // our test protocol, and it will run in a separate thread from the main
  40. // unit testing thread, so the DO requests can be serviced.
  41. @interface DOTestServer : NSObject <DOTestProtocol>
  42. - (void)runThread:(NSDictionary *)args;
  43. @end
  44. @implementation DOTestServer
  45. - (void)runThread:(NSDictionary *)args {
  46. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  47. NSConditionLock *lock = [args objectForKey:kGTMTransientRootLockKey];
  48. NSString *serverName = [args objectForKey:kGTMTransientRootNameKey];
  49. NSDate *future = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout];
  50. if(![lock lockWhenCondition:kGTMTransientThreadConditionStarting
  51. beforeDate:future]) {
  52. _GTMDevLog(@"Unable to acquire lock in runThread! This is BAD!");
  53. [pool drain];
  54. [NSThread exit];
  55. }
  56. NSConnection *conn = [[[NSConnection alloc] init] autorelease];
  57. [conn setRootObject:self];
  58. if (![conn registerName:serverName]) {
  59. _GTMDevLog(@"Failed to register DO root object with name '%@'",
  60. serverName);
  61. [pool drain];
  62. [NSThread exit];
  63. }
  64. [lock unlockWithCondition:kGTMTransientThreadConditionStarted];
  65. while (![lock tryLockWhenCondition:kGTMTransientThreadConditionQuitting]) {
  66. NSDate* runUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
  67. [[NSRunLoop currentRunLoop] runUntilDate:runUntil];
  68. }
  69. [conn setRootObject:nil];
  70. [conn registerName:nil];
  71. [pool drain];
  72. [lock unlockWithCondition:kGTMTransientThreadConditionQuitted];
  73. }
  74. - (oneway void)doOneWayVoid {
  75. // Do nothing
  76. }
  77. - (bycopy NSString *)doReturnStringBycopy {
  78. return @"TestString";
  79. }
  80. - (void)throwException {
  81. [NSException raise:@"testingException" format:@"for the unittest"];
  82. }
  83. @end
  84. // === Done with auxillary data structures, now for the main test class ===
  85. @interface GTMTransientRootProxy (GTMTransientRootProxyTest)
  86. - (id)init;
  87. @end
  88. @interface GTMTransientRootProxyTest : GTMTestCase {
  89. @private
  90. DOTestServer *server_;
  91. NSConditionLock *syncLock_;
  92. }
  93. @end
  94. @implementation GTMTransientRootProxyTest
  95. - (void)testTransientRootProxy {
  96. // Setup our server and create a unqiue server name every time we run
  97. NSTimeInterval timeStamp = [[NSDate date] timeIntervalSinceReferenceDate];
  98. NSString *serverName =
  99. [NSString stringWithFormat:@"%@_%f", kTestServerName, timeStamp];
  100. server_ = [[[DOTestServer alloc] init] autorelease];
  101. syncLock_ = [[[NSConditionLock alloc]
  102. initWithCondition:kGTMTransientThreadConditionStarting]
  103. autorelease];
  104. NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:
  105. syncLock_, kGTMTransientRootLockKey,
  106. serverName, kGTMTransientRootNameKey,
  107. nil];
  108. [NSThread detachNewThreadSelector:@selector(runThread:)
  109. toTarget:server_
  110. withObject:args];
  111. NSDate *future = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout];
  112. STAssertTrue([syncLock_ lockWhenCondition:kGTMTransientThreadConditionStarted
  113. beforeDate:future],
  114. @"Unable to start thread");
  115. [syncLock_ unlockWithCondition:kGTMTransientThreadConditionStarted];
  116. GTMTransientRootProxy *failProxy =
  117. [GTMTransientRootProxy rootProxyWithRegisteredName:nil
  118. host:nil
  119. protocol:@protocol(DOTestProtocol)
  120. requestTimeout:kDefaultTimeout
  121. replyTimeout:kDefaultTimeout];
  122. STAssertNil(failProxy, @"should have failed w/o a name");
  123. failProxy =
  124. [GTMTransientRootProxy rootProxyWithRegisteredName:serverName
  125. host:nil
  126. protocol:nil
  127. requestTimeout:kDefaultTimeout
  128. replyTimeout:kDefaultTimeout];
  129. STAssertNil(failProxy, @"should have failed w/o a protocol");
  130. failProxy = [[[GTMTransientRootProxy alloc] init] autorelease];
  131. STAssertNil(failProxy, @"should have failed just calling init");
  132. GTMTransientRootProxy<DOTestProtocol> *proxy =
  133. [GTMTransientRootProxy rootProxyWithRegisteredName:serverName
  134. host:nil
  135. protocol:@protocol(DOTestProtocol)
  136. requestTimeout:kDefaultTimeout
  137. replyTimeout:kDefaultTimeout];
  138. STAssertEqualObjects([proxy doReturnStringBycopy], @"TestString",
  139. @"proxy should have returned 'TestString'");
  140. // Redo the *exact* same test to make sure we can have multiple instances
  141. // in the same app.
  142. proxy =
  143. [GTMTransientRootProxy rootProxyWithRegisteredName:serverName
  144. host:nil
  145. protocol:@protocol(DOTestProtocol)
  146. requestTimeout:kDefaultTimeout
  147. replyTimeout:kDefaultTimeout];
  148. STAssertEqualObjects([proxy doReturnStringBycopy],
  149. @"TestString", @"proxy should have returned "
  150. @"'TestString'");
  151. // Test the GTMRootProxyCatchAll within this test so we don't have to rebuild
  152. // the server again.
  153. GTMRootProxyCatchAll<DOTestProtocol> *catchProxy =
  154. [GTMRootProxyCatchAll rootProxyWithRegisteredName:serverName
  155. host:nil
  156. protocol:@protocol(DOTestProtocol)
  157. requestTimeout:kDefaultTimeout
  158. replyTimeout:kDefaultTimeout];
  159. [GTMUnitTestDevLog expectString:@"Proxy for invoking throwException has "
  160. @"caught and is ignoring exception: [NOTE: this exception originated in "
  161. @"the server.]\nfor the unittest"];
  162. id e = nil;
  163. @try {
  164. // Has the server throw an exception
  165. [catchProxy throwException];
  166. } @catch (id ex) {
  167. e = ex;
  168. }
  169. STAssertNil(e, @"The GTMRootProxyCatchAll did not catch the exception: %@.",
  170. e);
  171. proxy =
  172. [GTMTransientRootProxy rootProxyWithRegisteredName:@"FAKE_SERVER"
  173. host:nil
  174. protocol:@protocol(DOTestProtocol)
  175. requestTimeout:kDefaultTimeout
  176. replyTimeout:kDefaultTimeout];
  177. STAssertNotNil(proxy, @"proxy shouldn't be nil, even when registered w/ a "
  178. @"fake server");
  179. STAssertFalse([proxy isConnected], @"the proxy shouldn't be connected due to "
  180. @"the fake server");
  181. // Now set up a proxy, and then kill our server. We put a super short time
  182. // out on it, because we are expecting it to fail.
  183. proxy =
  184. [GTMTransientRootProxy rootProxyWithRegisteredName:serverName
  185. host:nil
  186. protocol:@protocol(DOTestProtocol)
  187. requestTimeout:0.01
  188. replyTimeout:0.01];
  189. [syncLock_ tryLockWhenCondition:kGTMTransientThreadConditionStarted];
  190. [syncLock_ unlockWithCondition:kGTMTransientThreadConditionQuitting];
  191. // Wait for the server to shutdown so we clean up nicely.
  192. // The max amount of time we will wait until we abort this test.
  193. NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:kDefaultTimeout];
  194. // The server did not shutdown and we want to capture this as an error
  195. STAssertTrue([syncLock_ lockWhenCondition:kGTMTransientThreadConditionQuitted
  196. beforeDate:timeout],
  197. @"The server did not shutdown gracefully before the timeout.");
  198. [syncLock_ unlockWithCondition:kGTMTransientThreadConditionQuitted];
  199. // This should fail gracefully because the server is dead.
  200. STAssertNil([proxy doReturnStringBycopy], @"proxy should have returned nil");
  201. }
  202. @end