diff options
Diffstat (limited to 'Foundation/GTMHTTPFetcherTest.m')
-rw-r--r-- | Foundation/GTMHTTPFetcherTest.m | 516 |
1 files changed, 0 insertions, 516 deletions
diff --git a/Foundation/GTMHTTPFetcherTest.m b/Foundation/GTMHTTPFetcherTest.m deleted file mode 100644 index a541d1f..0000000 --- a/Foundation/GTMHTTPFetcherTest.m +++ /dev/null @@ -1,516 +0,0 @@ -// -// GTMHTTPFetcherTest.m -// -// Copyright 2007-2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -#import "GTMSenTestCase.h" -#import "GTMHTTPFetcher.h" -#import "GTMTestHTTPServer.h" -#import "GTMUnitTestDevLog.h" - -@interface GTMHTTPFetcherTest : GTMTestCase { - // these ivars are checked after fetches, and are reset by resetFetchResponse - NSData *fetchedData_; - NSError *fetcherError_; - NSInteger fetchedStatus_; - NSURLResponse *fetchedResponse_; - NSMutableURLRequest *fetchedRequest_; - - // setup/teardown ivars - NSMutableDictionary *fetchHistory_; - GTMTestHTTPServer *testServer_; -} -@end - -@interface GTMHTTPFetcherTest (PrivateMethods) -- (GTMHTTPFetcher *)doFetchWithURLString:(NSString *)urlString - cachingDatedData:(BOOL)doCaching; - -- (GTMHTTPFetcher *)doFetchWithURLString:(NSString *)urlString - cachingDatedData:(BOOL)doCaching - retrySelector:(SEL)retrySel - maxRetryInterval:(NSTimeInterval)maxRetryInterval - userData:(id)userData; - -- (NSString *)fileURLStringToTestFileName:(NSString *)name; -- (BOOL)countRetriesFetcher:(GTMHTTPFetcher *)fetcher - willRetry:(BOOL)suggestedWillRetry - forError:(NSError *)error; -- (BOOL)fixRequestFetcher:(GTMHTTPFetcher *)fetcher - willRetry:(BOOL)suggestedWillRetry - forError:(NSError *)error; -- (void)fetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data; -- (void)fetcher:(GTMHTTPFetcher *)fetcher failedWithError:(NSError *)error; -@end - -@implementation GTMHTTPFetcherTest - -static const NSTimeInterval kRunLoopInterval = 0.01; -// The bogus-fetch test can take >10s to pass. Pick something way higher -// to avoid failing. -static const NSTimeInterval kGiveUpInterval = 60.0; // bail on the test if 60 seconds elapse - -static NSString *const kValidFileName = @"GTMHTTPFetcherTestPage.html"; - -- (void)setUp { - fetchHistory_ = [[NSMutableDictionary alloc] init]; - - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - STAssertNotNil(testBundle, nil); - NSString *docRoot = [testBundle pathForResource:@"GTMHTTPFetcherTestPage" - ofType:@"html"]; - docRoot = [docRoot stringByDeletingLastPathComponent]; - STAssertNotNil(docRoot, nil); - - testServer_ = [[GTMTestHTTPServer alloc] initWithDocRoot:docRoot]; - STAssertNotNil(testServer_, @"failed to create a testing server"); -} - -- (void)resetFetchResponse { - [fetchedData_ release]; - fetchedData_ = nil; - - [fetcherError_ release]; - fetcherError_ = nil; - - [fetchedRequest_ release]; - fetchedRequest_ = nil; - - [fetchedResponse_ release]; - fetchedResponse_ = nil; - - fetchedStatus_ = 0; -} - -- (void)tearDown { - [testServer_ release]; - testServer_ = nil; - - [self resetFetchResponse]; - - [fetchHistory_ release]; - fetchHistory_ = nil; -} - -- (void)testValidFetch { - NSString *urlString = [self fileURLStringToTestFileName:kValidFileName]; - - GTMHTTPFetcher *fetcher = - [self doFetchWithURLString:urlString cachingDatedData:YES]; - - STAssertNotNil(fetchedData_, - @"failed to fetch data, status:%ld error:%@, URL:%@", - (long)fetchedStatus_, fetcherError_, urlString); - STAssertNotNil(fetchedResponse_, - @"failed to get fetch response, status:%ld error:%@", - (long)fetchedStatus_, fetcherError_); - STAssertNotNil(fetchedRequest_, @"failed to get fetch request, URL %@", - urlString); - STAssertNil(fetcherError_, @"fetching data gave error: %@", fetcherError_); - STAssertEquals(fetchedStatus_, (NSInteger)200, - @"fetching data expected status 200, instead got %ld, for URL %@", - (long)fetchedStatus_, urlString); - - // no cookies should be sent with our first request - NSDictionary *headers = [fetchedRequest_ allHTTPHeaderFields]; - NSString *cookiesSent = [headers objectForKey:@"Cookie"]; - STAssertNil(cookiesSent, @"Cookies sent unexpectedly: %@", cookiesSent); - - - // cookies should have been set by the response; specifically, TestCookie - // should be set to the name of the file requested - NSDictionary *responseHeaders; - - responseHeaders = [(NSHTTPURLResponse *)fetchedResponse_ allHeaderFields]; - NSString *cookiesSetString = [responseHeaders objectForKey:@"Set-Cookie"]; - NSString *cookieExpected = [NSString stringWithFormat:@"TestCookie=%@", - kValidFileName]; - STAssertEqualObjects(cookiesSetString, cookieExpected, @"Unexpected cookie"); - - // test properties - NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: - @"val1", @"key1", @"val2", @"key2", nil]; - [fetcher setProperties:dict]; - STAssertEqualObjects([fetcher properties], dict, @"properties as dictionary"); - STAssertEqualObjects([fetcher propertyForKey:@"key2"], @"val2", - @"single property"); - - NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys: - @"valx1", @"key1", @"val3", @"key3", nil]; - [fetcher setProperty:@"valx1" forKey:@"key1"]; - [fetcher setProperty:nil forKey:@"key2"]; - [fetcher setProperty:@"val3" forKey:@"key3"]; - STAssertEqualObjects([fetcher properties], dict2, @"property changes"); - - // make a copy of the fetched data to compare with our next fetch from the - // cache - NSData *originalFetchedData = [[fetchedData_ copy] autorelease]; - - // Now fetch again so the "If modified since" header will be set (because - // we're calling setFetchHistory: below) and caching ON, and verify that we - // got a good data from the cache, along with a "Not modified" status - - [self resetFetchResponse]; - - [self doFetchWithURLString:urlString cachingDatedData:YES]; - - STAssertEqualObjects(fetchedData_, originalFetchedData, - @"cache data mismatch"); - - STAssertNotNil(fetchedData_, - @"failed to fetch data, status:%ld error:%@, URL:%@", - (long)fetchedStatus_, fetcherError_, urlString); - STAssertNotNil(fetchedResponse_, - @"failed to get fetch response, status:%;d error:%@", - (long)fetchedStatus_, fetcherError_); - STAssertNotNil(fetchedRequest_, @"failed to get fetch request, URL %@", - urlString); - STAssertNil(fetcherError_, @"fetching data gave error: %@", fetcherError_); - - STAssertEquals(fetchedStatus_, (NSInteger)kGTMHTTPFetcherStatusNotModified, // 304 - @"fetching data expected status 304, instead got %ld, for URL %@", - (long)fetchedStatus_, urlString); - - // the TestCookie set previously should be sent with this request - cookiesSent = [[fetchedRequest_ allHTTPHeaderFields] objectForKey:@"Cookie"]; - STAssertEqualObjects(cookiesSent, cookieExpected, @"Cookie not sent"); - - // Now fetch twice without caching enabled, and verify that we got a - // "Not modified" status, along with a non-nil but empty NSData (which - // is normal for that status code) - - [self resetFetchResponse]; - - [fetchHistory_ removeAllObjects]; - - [self doFetchWithURLString:urlString cachingDatedData:NO]; - - STAssertEqualObjects(fetchedData_, originalFetchedData, - @"cache data mismatch"); - - [self resetFetchResponse]; - [self doFetchWithURLString:urlString cachingDatedData:NO]; - - STAssertNotNil(fetchedData_, @""); - STAssertEquals([fetchedData_ length], (NSUInteger)0, @"unexpected data"); - STAssertEquals(fetchedStatus_, (NSInteger)kGTMHTTPFetcherStatusNotModified, - @"fetching data expected status 304, instead got %d", fetchedStatus_); - STAssertNil(fetcherError_, @"unexpected error: %@", fetcherError_); - -} - -- (void)testBogusFetch { - // fetch a live, invalid URL - NSString *badURLString = @"http://localhost:86/"; - [self doFetchWithURLString:badURLString cachingDatedData:NO]; - - const int kServiceUnavailableStatus = 503; - - if (fetchedStatus_ == kServiceUnavailableStatus) { - // some proxies give a "service unavailable" error for bogus fetches - } else { - - if (fetchedData_) { - NSString *str = [[[NSString alloc] initWithData:fetchedData_ - encoding:NSUTF8StringEncoding] autorelease]; - STAssertNil(fetchedData_, @"fetched unexpected data: %@", str); - } - - STAssertNotNil(fetcherError_, @"failed to receive fetching error"); - STAssertEquals(fetchedStatus_, (NSInteger)0, - @"fetching data expected no status from no response, instead got %d", - fetchedStatus_); - } - - // fetch with a specific status code from our http server - [self resetFetchResponse]; - - NSString *invalidWebPageFile = - [kValidFileName stringByAppendingString:@"?status=400"]; - NSString *statusUrlString = - [self fileURLStringToTestFileName:invalidWebPageFile]; - - [self doFetchWithURLString:statusUrlString cachingDatedData:NO]; - - STAssertNotNil(fetchedData_, @"fetch lacked data with error info"); - STAssertNil(fetcherError_, @"expected bad status but got an error"); - STAssertEquals(fetchedStatus_, (NSInteger)400, - @"unexpected status, error=%@", fetcherError_); -} - -- (void)testRetryFetches { - GTMHTTPFetcher *fetcher; - - NSString *invalidFile = [kValidFileName stringByAppendingString:@"?status=503"]; - NSString *urlString = [self fileURLStringToTestFileName:invalidFile]; - - SEL countRetriesSel = @selector(countRetriesFetcher:willRetry:forError:); - SEL fixRequestSel = @selector(fixRequestFetcher:willRetry:forError:); - - // - // test: retry until timeout, then expect failure with status message - // - - NSNumber *lotsOfRetriesNumber = [NSNumber numberWithInt:1000]; - - fetcher= [self doFetchWithURLString:urlString - cachingDatedData:NO - retrySelector:countRetriesSel - maxRetryInterval:5.0 // retry intervals of 1, 2, 4 - userData:lotsOfRetriesNumber]; - - STAssertNotNil(fetchedData_, @"error data is expected"); - STAssertEquals(fetchedStatus_, (NSInteger)503, nil); - STAssertEquals([fetcher retryCount], 3U, @"retry count unexpected"); - - // - // test: retry twice, then give up - // - [self resetFetchResponse]; - - NSNumber *twoRetriesNumber = [NSNumber numberWithInt:2]; - - fetcher= [self doFetchWithURLString:urlString - cachingDatedData:NO - retrySelector:countRetriesSel - maxRetryInterval:10.0 // retry intervals of 1, 2, 4, 8 - userData:twoRetriesNumber]; - - STAssertNotNil(fetchedData_, @"error data is expected"); - STAssertEquals(fetchedStatus_, (NSInteger)503, nil); - STAssertEquals([fetcher retryCount], 2U, @"retry count unexpected"); - - - // - // test: retry, making the request succeed on the first retry - // by fixing the URL - // - [self resetFetchResponse]; - - fetcher= [self doFetchWithURLString:urlString - cachingDatedData:NO - retrySelector:fixRequestSel - maxRetryInterval:30.0 // should only retry once due to selector - userData:lotsOfRetriesNumber]; - - STAssertNotNil(fetchedData_, @"data is expected"); - STAssertEquals(fetchedStatus_, (NSInteger)200, nil); - STAssertEquals([fetcher retryCount], 1U, @"retry count unexpected"); -} - -- (void)testNilFetch { - GTMHTTPFetcher *fetcher = [[GTMHTTPFetcher alloc] init]; - [GTMUnitTestDevLog expectString:@"beginFetchWithDelegate requires a request"]; - BOOL wasGood = [fetcher beginFetchWithDelegate:nil - didFinishSelector:NULL - didFailSelector:NULL]; - STAssertFalse(wasGood, nil); -} - -- (void)testCookies { - // This is checking part one of - // rdar://6293862 NSHTTPCookie cookieWithProperties doesn't work with - // NSHTTPCookieOriginURL key - NSString *urlString = @"http://www.apple.com/index.html"; - NSURL *url = [NSURL URLWithString:@"http://www.apple.com/index.html"]; - - NSDictionary *properties = [NSDictionary dictionaryWithObjectsAndKeys: - url, NSHTTPCookieOriginURL, - @"testCookies", NSHTTPCookieName, - @"1", NSHTTPCookieValue, - nil]; - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:properties]; - - STAssertNil(cookie, nil); - - // This is checking part two of - // rdar://6293862 NSHTTPCookie cookieWithProperties doesn't work with - // NSHTTPCookieOriginURL key - properties = [NSDictionary dictionaryWithObjectsAndKeys: - urlString, NSHTTPCookieOriginURL, - @"testCookies", NSHTTPCookieName, - @"1", NSHTTPCookieValue, - nil]; - cookie = [NSHTTPCookie cookieWithProperties:properties]; - - STAssertNil(cookie, nil); -} - -#pragma mark - - -- (GTMHTTPFetcher *)doFetchWithURLString:(NSString *)urlString - cachingDatedData:(BOOL)doCaching { - - return [self doFetchWithURLString:(NSString *)urlString - cachingDatedData:(BOOL)doCaching - retrySelector:nil - maxRetryInterval:0 - userData:nil]; -} - -- (GTMHTTPFetcher *)doFetchWithURLString:(NSString *)urlString - cachingDatedData:(BOOL)doCaching - retrySelector:(SEL)retrySel - maxRetryInterval:(NSTimeInterval)maxRetryInterval - userData:(id)userData { - - NSURL *url = [NSURL URLWithString:urlString]; - NSURLRequest *req = [NSURLRequest requestWithURL:url - cachePolicy:NSURLRequestReloadIgnoringCacheData - timeoutInterval:kGiveUpInterval]; - GTMHTTPFetcher *fetcher = [GTMHTTPFetcher httpFetcherWithRequest:req]; - - STAssertNotNil(fetcher, @"Failed to allocate fetcher"); - - // setting the fetch history will add the "If-modified-since" header - // to repeat requests - [fetcher setFetchHistory:fetchHistory_]; - if (doCaching != [fetcher shouldCacheDatedData]) { - // only set the value when it changes since setting it to nil clears out - // some of the state and our tests need the state between some non caching - // fetches. - [fetcher setShouldCacheDatedData:doCaching]; - } - - if (retrySel) { - [fetcher setIsRetryEnabled:YES]; - [fetcher setRetrySelector:retrySel]; - [fetcher setMaxRetryInterval:maxRetryInterval]; - [fetcher setUserData:userData]; - - // we force a minimum retry interval for unit testing; otherwise, - // we'd have no idea how many retries will occur before the max - // retry interval occurs, since the minimum would be random - [fetcher setMinRetryInterval:1.0]; - } - - BOOL isFetching = - [fetcher beginFetchWithDelegate:self - didFinishSelector:@selector(fetcher:finishedWithData:) - didFailSelector:@selector(fetcher:failedWithError:)]; - STAssertTrue(isFetching, @"Begin fetch failed"); - - if (isFetching) { - - // Give time for the fetch to happen, but give up if 10 seconds elapse with - // no response - NSDate* giveUpDate = [NSDate dateWithTimeIntervalSinceNow:kGiveUpInterval]; - while ((!fetchedData_ && !fetcherError_) && - [giveUpDate timeIntervalSinceNow] > 0) { - NSDate* loopIntervalDate = - [NSDate dateWithTimeIntervalSinceNow:kRunLoopInterval]; - [[NSRunLoop currentRunLoop] runUntilDate:loopIntervalDate]; - } - } - - return fetcher; -} - -- (NSString *)fileURLStringToTestFileName:(NSString *)name { - - // we need to create http URLs referring to the desired - // resource to be found by the python http server running locally - - // return a localhost:port URL for the test file - NSString *urlString = [NSString stringWithFormat:@"http://localhost:%d/%@", - [testServer_ port], name]; - - // we exclude the "?status=" that would indicate that the URL - // should cause a retryable error - NSRange range = [name rangeOfString:@"?status="]; - if (range.length > 0) { - name = [name substringToIndex:range.location]; - } - - // we exclude the ".auth" extension that would indicate that the URL - // should be tested with authentication - if ([[name pathExtension] isEqual:@"auth"]) { - name = [name stringByDeletingPathExtension]; - } - - // just for sanity, let's make sure we see the file locally, so - // we can expect the Python http server to find it too - NSBundle *testBundle = [NSBundle bundleForClass:[self class]]; - STAssertNotNil(testBundle, nil); - - NSString *filePath = - [testBundle pathForResource:[name stringByDeletingPathExtension] - ofType:[name pathExtension]]; - STAssertNotNil(filePath, nil); - - return urlString; -} - - - -- (void)fetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data { - fetchedData_ = [data copy]; - fetchedStatus_ = [fetcher statusCode]; // this implicitly tests that the fetcher has kept the response - fetchedRequest_ = [[fetcher request] retain]; - fetchedResponse_ = [[fetcher response] retain]; -} - -- (void)fetcher:(GTMHTTPFetcher *)fetcher failedWithError:(NSError *)error { - // if it's a status error, don't hang onto the error, just the status/data - if ([[error domain] isEqual:kGTMHTTPFetcherStatusDomain]) { - fetchedData_ = [[[error userInfo] objectForKey:kGTMHTTPFetcherStatusDataKey] copy]; - fetchedStatus_ = [error code]; // this implicitly tests that the fetcher has kept the response - } else { - fetcherError_ = [error retain]; - fetchedStatus_ = [fetcher statusCode]; - } -} - - -// Selector for allowing up to N retries, where N is an NSNumber in the -// fetcher's userData -- (BOOL)countRetriesFetcher:(GTMHTTPFetcher *)fetcher - willRetry:(BOOL)suggestedWillRetry - forError:(NSError *)error { - - int count = [fetcher retryCount]; - int allowedRetryCount = [[fetcher userData] intValue]; - - BOOL shouldRetry = (count < allowedRetryCount); - - STAssertEquals([fetcher nextRetryInterval], pow(2.0, [fetcher retryCount]), - @"unexpected next retry interval (expected %f, was %f)", - pow(2.0, [fetcher retryCount]), - [fetcher nextRetryInterval]); - - return shouldRetry; -} - -// Selector for retrying and changing the request to one that will succeed -- (BOOL)fixRequestFetcher:(GTMHTTPFetcher *)fetcher - willRetry:(BOOL)suggestedWillRetry - forError:(NSError *)error { - - STAssertEquals([fetcher nextRetryInterval], pow(2.0, [fetcher retryCount]), - @"unexpected next retry interval (expected %f, was %f)", - pow(2.0, [fetcher retryCount]), - [fetcher nextRetryInterval]); - - // fix it - change the request to a URL which does not have a status value - NSString *urlString = [self fileURLStringToTestFileName:kValidFileName]; - - NSURL *url = [NSURL URLWithString:urlString]; - [fetcher setRequest:[NSURLRequest requestWithURL:url]]; - - return YES; // do the retry fetch; it should succeed now -} - -@end |