PageRenderTime 107ms CodeModel.GetById 18ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 0ms

/core/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
 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