PageRenderTime 120ms CodeModel.GetById 17ms app.highlight 99ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/externals/gdata-objectivec-client/Source/HTTPFetcher/Tests/GTMHTTPFetcherServiceTest.m

http://macfuse.googlecode.com/
Objective C | 316 lines | 212 code | 59 blank | 45 comment | 19 complexity | 185e37054bdf93a13df3cee4290ff44b MD5 | raw file
  1/* Copyright (c) 2011 Google Inc.
  2 *
  3 * Licensed under the Apache License, Version 2.0 (the "License");
  4 * you may not use this file except in compliance with the License.
  5 * You may obtain a copy of the License at
  6 *
  7 *     http://www.apache.org/licenses/LICENSE-2.0
  8 *
  9 * Unless required by applicable law or agreed to in writing, software
 10 * distributed under the License is distributed on an "AS IS" BASIS,
 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 * See the License for the specific language governing permissions and
 13 * limitations under the License.
 14 */
 15
 16#import <XCTest/XCTest.h>
 17
 18#import "GTMHTTPFetcherTestServer.h"
 19#import "GTMHTTPFetcherService.h"
 20
 21@interface GTMHTTPFetcherServiceTest : XCTestCase {
 22  GTMHTTPFetcherTestServer *testServer_;
 23  BOOL isServerRunning_;
 24}
 25
 26@end
 27
 28@implementation GTMHTTPFetcherServiceTest
 29
 30// file available in Tests folder
 31static NSString *const kValidFileName = @"gettysburgaddress.txt";
 32
 33- (NSString *)docRootPath {
 34  // find a test file
 35  NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
 36  XCTAssertNotNil(testBundle);
 37
 38  // use the directory of the test file as the root directory for our server
 39  NSString *docFolder = [testBundle resourcePath];
 40  return docFolder;
 41}
 42
 43- (void)setUp {
 44  NSString *docRoot = [self docRootPath];
 45
 46  testServer_ = [[GTMHTTPFetcherTestServer alloc] initWithDocRoot:docRoot];
 47  isServerRunning_ = (testServer_ != nil);
 48
 49  XCTAssertTrue(isServerRunning_,
 50               @">>> http test server failed to launch; skipping"
 51               " service tests\n");
 52}
 53
 54- (void)tearDown {
 55  [testServer_ release];
 56  testServer_ = nil;
 57
 58  isServerRunning_ = NO;
 59}
 60
 61- (void)testFetcherService {
 62  if (!isServerRunning_) return;
 63
 64  // Utility blocks for counting array entries for a specific host
 65  NSUInteger (^URLsPerHost) (NSArray *, NSString *) = ^(NSArray *URLs,
 66                                                        NSString *host) {
 67    NSUInteger counter = 0;
 68    for (NSURL *url in URLs) {
 69      if ([host isEqual:[url host]]) counter++;
 70    }
 71    return counter;
 72  };
 73  
 74  NSUInteger (^FetchersPerHost) (NSArray *, NSString *) = ^(NSArray *fetchers,
 75                                                            NSString *host) {
 76    NSArray *fetcherURLs = [fetchers valueForKeyPath:@"mutableRequest.URL"];
 77    return URLsPerHost(fetcherURLs, host);
 78  };
 79
 80  // Utility block for finding the minimum priority fetcher for a specific host
 81  NSInteger (^PriorityPerHost) (NSArray *, NSString *) = ^(NSArray *fetchers,
 82                                                            NSString *host) {
 83    NSInteger val = NSIntegerMax;
 84    for (GTMHTTPFetcher *fetcher in fetchers) {
 85      if ([host isEqual:[[fetcher.mutableRequest URL] host]]) {
 86        val = MIN(val, fetcher.servicePriority);
 87      }
 88    }
 89    return val;
 90  };
 91
 92  // We'll verify we fetched from the server the same data that is on disk
 93  NSString *gettysburgPath = [testServer_ localPathForFile:kValidFileName];
 94  NSData *gettysburgAddress = [NSData dataWithContentsOfFile:gettysburgPath];
 95
 96  NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 97
 98  // We'll create 10 fetchers.  Only 2 should run simultaneously.
 99  // 1 should fail; the rest should succeeed.
100  const NSUInteger kMaxRunningFetchersPerHost = 2;
101
102  NSString *const kUserAgent = @"ServiceTest-UA";
103  const NSTimeInterval kTimeout = 55;
104
105  GTMHTTPFetcherService *service = [[[GTMHTTPFetcherService alloc] init] autorelease];
106  service.maxRunningFetchersPerHost = kMaxRunningFetchersPerHost;
107  service.fetchHistory.shouldRememberETags = NO;
108  service.userAgent = kUserAgent;
109  service.timeout = kTimeout;
110
111  // Make URLs for a valid fetch, a fetch that returns a status error,
112  // and a valid fetch with a different host
113  NSURL *validFileURL = [testServer_ localURLForFile:kValidFileName];
114
115  NSString *invalidFile = [kValidFileName stringByAppendingString:@"?status=400"];
116  NSURL *invalidFileURL = [testServer_ localURLForFile:invalidFile];
117
118  NSString *validURLStr = [validFileURL absoluteString];
119  NSString *altValidURLStr = [validURLStr stringByReplacingOccurrencesOfString:@"localhost"
120                                                                    withString:@"127.0.0.1"];
121  NSURL *altValidURL = [NSURL URLWithString:altValidURLStr];
122
123  XCTAssertEqualObjects([validFileURL host], @"localhost", @"unexpected host");
124  XCTAssertEqualObjects([invalidFileURL host], @"localhost", @"unexpected host");
125  XCTAssertEqualObjects([altValidURL host], @"127.0.0.1", @"unexpected host");
126
127  // Make an array with the urls from the different hosts, including one
128  // that will fail with a status 400 error
129  NSMutableArray *urlArray = [NSMutableArray array];
130  for (int idx = 1; idx <= 4; idx++) [urlArray addObject:validFileURL];
131  [urlArray addObject:invalidFileURL];
132  for (int idx = 1; idx <= 5; idx++) [urlArray addObject:validFileURL];
133  for (int idx = 1; idx <= 5; idx++) [urlArray addObject:altValidURL];
134  for (int idx = 1; idx <= 5; idx++) [urlArray addObject:validFileURL];
135  NSUInteger totalNumberOfFetchers = [urlArray count];
136
137  __block NSMutableArray *pending = [NSMutableArray array];
138  __block NSMutableArray *running = [NSMutableArray array];
139  __block NSMutableArray *completed = [NSMutableArray array];
140
141  NSUInteger priorityVal = 0;
142
143  // Create all the fetchers
144  for (NSURL *fileURL in urlArray) {
145    GTMHTTPFetcher *fetcher = [service fetcherWithURL:fileURL];
146
147    // Fetcher start notification
148    [nc addObserverForName:kGTMHTTPFetcherStartedNotification
149                    object:fetcher
150                     queue:nil
151                usingBlock:^(NSNotification *note) {
152                  // Verify that we have at most two fetchers running for this
153                  // fetcher's host
154                  [running addObject:fetcher];
155                  [pending removeObject:fetcher];
156
157                  NSMutableURLRequest *fetcherReq = [fetcher mutableRequest];
158                  NSURL *fetcherReqURL = [fetcherReq URL];
159                  NSString *host = [fetcherReqURL host];
160                  NSUInteger numberRunning = FetchersPerHost(running, host);
161                  XCTAssertTrue(numberRunning > 0, @"count error");
162                  XCTAssertTrue(numberRunning <= kMaxRunningFetchersPerHost,
163                               @"too many running");
164
165                  NSInteger pendingPriority = PriorityPerHost(pending, host);
166                  XCTAssertTrue(fetcher.servicePriority <= pendingPriority,
167                               @"a pending fetcher has greater priority");
168
169                  XCTAssertEqual([service numberOfFetchers],
170                                 [running count] + [pending count],
171                                 @"fetcher count off");
172                  XCTAssertEqual([service numberOfRunningFetchers],
173                                 [running count], @"running off");
174                  XCTAssertEqual([service numberOfDelayedFetchers],
175                                 [pending count], @"delayed off");
176
177                  NSArray *matches =
178                    [service issuedFetchersWithRequestURL:fetcherReqURL];
179                  NSUInteger idx = NSNotFound;
180                  if (matches) {
181                    idx = [matches indexOfObjectIdenticalTo:fetcher];
182                  }
183                  XCTAssertTrue(idx != NSNotFound, @"Missing %@ in %@",
184                               fetcherReqURL, matches);
185                  NSURL *fakeURL =
186                    [NSURL URLWithString:@"http://example.com/bad"];
187                  matches = [service issuedFetchersWithRequestURL:fakeURL];
188                  XCTAssertEqual([matches count], (NSUInteger)0);
189
190                  NSString *agent = [fetcherReq valueForHTTPHeaderField:@"User-Agent"];
191                  XCTAssertEqualObjects(agent, kUserAgent);
192                  XCTAssertEqual([fetcherReq timeoutInterval], kTimeout);
193                }];
194
195    // Fetcher stopped notification
196    [nc addObserverForName:kGTMHTTPFetcherStoppedNotification
197                    object:fetcher
198                     queue:nil
199                usingBlock:^(NSNotification *note) {
200                  // Verify that we only have two fetchers running
201                  [completed addObject:fetcher];
202                  [running removeObject:fetcher];
203
204                  NSString *host = [[[fetcher mutableRequest] URL] host];
205
206                  NSUInteger numberRunning = FetchersPerHost(running, host);
207                  NSUInteger numberPending = FetchersPerHost(pending, host);
208                  NSUInteger numberCompleted = FetchersPerHost(completed, host);
209
210                  XCTAssertTrue(numberRunning <= kMaxRunningFetchersPerHost,
211                               @"too many running");
212                  XCTAssertTrue(numberPending + numberRunning + numberCompleted <= URLsPerHost(urlArray, host),
213                               @"%d issued running (pending:%u running:%u completed:%u)",
214                               (unsigned int)totalNumberOfFetchers, (unsigned int)numberPending,
215                               (unsigned int)numberRunning, (unsigned int)numberCompleted);
216
217                  XCTAssertEqual([service numberOfFetchers],
218                                 [running count] + [pending count] + 1,
219                                 @"fetcher count off");
220                  XCTAssertEqual([service numberOfRunningFetchers],
221                                 [running count] + 1, @"running off");
222                  XCTAssertEqual([service numberOfDelayedFetchers],
223                                 [pending count], @"delayed off");
224                }];
225
226    [pending addObject:fetcher];
227
228    // Set the fetch priority to a value that cycles 0, 1, -1, 0, ...
229    priorityVal++;
230    if (priorityVal > 1) priorityVal = -1;
231    fetcher.servicePriority = priorityVal;
232
233    // Start this fetcher
234    [fetcher beginFetchWithCompletionHandler:^(NSData *fetchData, NSError *fetchError) {
235      // Callback
236      //
237      // The query should be empty except for the URL with a status code
238      NSString *query = [[[fetcher mutableRequest] URL] query];
239      BOOL isValidRequest = ([query length] == 0);
240      if (isValidRequest) {
241        XCTAssertEqualObjects(fetchData, gettysburgAddress,
242                             @"Bad fetch data");
243        XCTAssertNil(fetchError, @"unexpected %@ %@",
244                    fetchError, [fetchError userInfo]);
245      } else {
246        // This is the query with ?status=400
247        XCTAssertEqual([fetchError code], (NSInteger) 400, @"expected error");
248      }
249    }];
250  }
251
252  [service waitForCompletionOfAllFetchersWithTimeout:10];
253
254  XCTAssertEqual([pending count], (NSUInteger) 0,
255                 @"still pending: %@", pending);
256  XCTAssertEqual([running count], (NSUInteger) 0,
257                 @"still running: %@", running);
258  XCTAssertEqual([completed count], (NSUInteger) totalNumberOfFetchers,
259                 @"incomplete");
260
261  XCTAssertEqual([service numberOfFetchers], (NSUInteger) 0,
262                 @"service non-empty");
263}
264
265- (void)testStopAllFetchers {
266  if (!isServerRunning_) return;
267
268  GTMHTTPFetcherService *service = [[[GTMHTTPFetcherService alloc] init] autorelease];
269  service.maxRunningFetchersPerHost = 2;
270  service.fetchHistory.shouldRememberETags = NO;
271
272  // Create three fetchers for each of two URLs, so there should be
273  // two running and one delayed for each
274  NSURL *validFileURL = [testServer_ localURLForFile:kValidFileName];
275
276  NSString *validURLStr = [validFileURL absoluteString];
277  NSString *altValidURLStr = [validURLStr stringByReplacingOccurrencesOfString:@"localhost"
278                                                                    withString:@"127.0.0.1"];
279  NSURL *altValidURL = [NSURL URLWithString:altValidURLStr];
280
281  // Add three fetches for each URL
282  NSMutableArray *urlArray = [NSMutableArray array];
283  [urlArray addObject:validFileURL];
284  [urlArray addObject:altValidURL];
285  [urlArray addObject:validFileURL];
286  [urlArray addObject:altValidURL];
287  [urlArray addObject:validFileURL];
288  [urlArray addObject:altValidURL];
289
290  // Create and start all the fetchers
291  for (NSURL *fileURL in urlArray) {
292    GTMHTTPFetcher *fetcher = [service fetcherWithURL:fileURL];
293    [fetcher beginFetchWithCompletionHandler:^(NSData *fetchData, NSError *fetchError) {
294      // We shouldn't reach any of the callbacks
295      XCTFail(@"Fetcher completed but should have been stopped");
296    }];
297  }
298
299  // Two hosts
300  XCTAssertEqual([service.runningHosts count], (NSUInteger)2, @"hosts running");
301  XCTAssertEqual([service.delayedHosts count], (NSUInteger)2, @"hosts delayed");
302
303  // We should see two fetchers running and one delayed for each host
304  NSArray *localhosts = [service.runningHosts objectForKey:@"localhost"];
305  XCTAssertEqual([localhosts count], (NSUInteger)2, @"hosts running");
306
307  localhosts = [service.delayedHosts objectForKey:@"localhost"];
308  XCTAssertEqual([localhosts count], (NSUInteger)1, @"hosts delayed");
309
310  [service stopAllFetchers];
311
312  XCTAssertEqual([service.runningHosts count], (NSUInteger)0, @"hosts running");
313  XCTAssertEqual([service.delayedHosts count], (NSUInteger)0, @"hosts delayed");
314}
315
316@end