PageRenderTime 124ms CodeModel.GetById 60ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 1ms

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