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