Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / ios / chrome / browser / snapshots / snapshot_cache_unittest.mm
blobc77a9ae94f56d7d2b24d2c93758101c6001a9901
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
7 #import <Foundation/Foundation.h>
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/format_macros.h"
12 #include "base/ios/ios_util.h"
13 #include "base/location.h"
14 #include "base/mac/bind_objc_block.h"
15 #include "base/mac/scoped_nsautorelease_pool.h"
16 #include "base/run_loop.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/time/time.h"
19 #include "ios/chrome/browser/ui/ui_util.h"
20 #include "ios/web/public/test/test_web_thread_bundle.h"
21 #include "ios/web/public/web_thread.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "testing/gtest_mac.h"
24 #include "testing/platform_test.h"
26 static const NSUInteger kSessionCount = 10;
27 static const NSUInteger kSnapshotPixelSize = 8;
29 // Promote some implementation methods to public.
30 @interface SnapshotCache (Testing)
31 + (base::FilePath)imagePathForSessionID:(NSString*)sessionID;
32 + (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID;
33 - (void)handleLowMemory;
34 @end
36 @interface SnapshotCache (TestingAdditions)
37 - (BOOL)hasImageInMemory:(NSString*)sessionID;
38 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID;
39 @end
41 @implementation SnapshotCache (TestingAdditions)
42 - (BOOL)hasImageInMemory:(NSString*)sessionID {
43   return [imageDictionary_ objectForKey:sessionID] != nil;
45 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID {
46   return [greyImageDictionary_ objectForKey:sessionID] != nil;
48 @end
50 namespace {
52 class SnapshotCacheTest : public PlatformTest {
53  protected:
54   // Build an array of session names and an array of UIImages filled with
55   // random colors.
56   void SetUp() override {
57     PlatformTest::SetUp();
58     snapshotCache_.reset([[SnapshotCache alloc] init]);
59     testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]);
60     testSessions_.reset(
61         [[NSMutableArray alloc] initWithCapacity:kSessionCount]);
63     CGFloat scale = [SnapshotCache snapshotScaleForDevice];
64     UIGraphicsBeginImageContextWithOptions(
65         CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale);
66     CGContextRef context = UIGraphicsGetCurrentContext();
67     srand(1);
69     for (NSUInteger i = 0; i < kSessionCount; ++i) {
70       UIImage* image = GenerateRandomImage(context);
71       [testImages_ addObject:image];
72       [testSessions_
73           addObject:[NSString stringWithFormat:@"SessionId-%" PRIuNS, i]];
74     }
76     UIGraphicsEndImageContext();
78     ClearDumpedImages();
79   }
81   void TearDown() override {
82     ClearDumpedImages();
83     snapshotCache_.reset();
84     PlatformTest::TearDown();
85   }
87   SnapshotCache* GetSnapshotCache() {
88     return snapshotCache_.get();
89   }
91   // Generates an image filled with a random color.
92   UIImage* GenerateRandomImage(CGContextRef context) {
93     CGFloat r = rand() / CGFloat(RAND_MAX);
94     CGFloat g = rand() / CGFloat(RAND_MAX);
95     CGFloat b = rand() / CGFloat(RAND_MAX);
96     CGContextSetRGBStrokeColor(context, r, g, b, 1.0);
97     CGContextSetRGBFillColor(context, r, g, b, 1.0);
98     CGContextFillRect(
99         context, CGRectMake(0.0, 0.0, kSnapshotPixelSize, kSnapshotPixelSize));
100     return UIGraphicsGetImageFromCurrentImageContext();
101   }
103   // Flushes all the runloops internally used by the snapshot cache.
104   void FlushRunLoops() {
105     base::RunLoop().RunUntilIdle();
106     web::WebThread::GetBlockingPool()->FlushForTesting();
107     base::RunLoop().RunUntilIdle();
108   }
110   // This function removes the snapshots both from dictionary and from disk.
111   void ClearDumpedImages() {
112     SnapshotCache* cache = GetSnapshotCache();
114     NSString* sessionID;
115     for (sessionID in testSessions_.get())
116       [cache removeImageWithSessionID:sessionID];
118     FlushRunLoops();
119     // The above calls to -removeImageWithSessionID remove both the color
120     // and grey snapshots for each sessionID, if they are on disk.  However,
121     // ensure we also get rid of the grey snapshots in memory.
122     [cache removeGreyCache];
124     __block BOOL foundImage = NO;
125     __block NSUInteger numCallbacks = 0;
126     for (sessionID in testSessions_.get()) {
127       base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]);
129       // Checks that the snapshot is not on disk.
130       EXPECT_FALSE(base::PathExists(path));
132       // Check that the snapshot is not in the dictionary.
133       [cache retrieveImageForSessionID:sessionID
134                               callback:^(UIImage* image) {
135                                 ++numCallbacks;
136                                 if (image)
137                                   foundImage = YES;
138                               }];
139     }
141     // Expect that all the callbacks ran and that none retrieved an image.
142     FlushRunLoops();
143     EXPECT_EQ([testSessions_ count], numCallbacks);
144     EXPECT_FALSE(foundImage);
145   }
147   // Loads kSessionCount color images into the cache.  If |waitForFilesOnDisk|
148   // is YES, will not return until the images have been written to disk.
149   void LoadAllColorImagesIntoCache(bool waitForFilesOnDisk) {
150     LoadColorImagesIntoCache(kSessionCount, waitForFilesOnDisk);
151   }
153   // Loads |count| color images into the cache.  If |waitForFilesOnDisk|
154   // is YES, will not return until the images have been written to disk.
155   void LoadColorImagesIntoCache(NSUInteger count, bool waitForFilesOnDisk) {
156     SnapshotCache* cache = GetSnapshotCache();
157     // Put color images in the cache.
158     for (NSUInteger i = 0; i < count; ++i) {
159       base::mac::ScopedNSAutoreleasePool pool;
160       UIImage* image = [testImages_ objectAtIndex:i];
161       NSString* sessionID = [testSessions_ objectAtIndex:i];
162       [cache setImage:image withSessionID:sessionID];
163     }
164     if (waitForFilesOnDisk) {
165       FlushRunLoops();
166       for (NSUInteger i = 0; i < count; ++i) {
167         // Check that images are on the disk.
168         NSString* sessionID = [testSessions_ objectAtIndex:i];
169         base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]);
170         EXPECT_TRUE(base::PathExists(path));
171       }
172     }
173   }
175   // Waits for the first |count| grey images for sessions in |testSessions_|
176   // to be placed in the cache.
177   void WaitForGreyImagesInCache(NSUInteger count) {
178     SnapshotCache* cache = GetSnapshotCache();
179     FlushRunLoops();
180     for (NSUInteger i = 0; i < count; i++)
181       EXPECT_TRUE([cache hasGreyImageInMemory:testSessions_[i]]);
182   }
184   // Guesses the order of the color channels in the image.
185   // Supports RGB, BGR, RGBA, BGRA, ARGB, ABGR.
186   // Returns the position of each channel between 0 and 3.
187   void ComputeColorComponents(CGImageRef cgImage,
188                               int* red,
189                               int* green,
190                               int* blue) {
191     CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
192     CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage);
193     int byteOrder = bitmapInfo & kCGBitmapByteOrderMask;
195     *red = 0;
196     *green = 1;
197     *blue = 2;
199     if (alphaInfo == kCGImageAlphaLast ||
200         alphaInfo == kCGImageAlphaPremultipliedLast ||
201         alphaInfo == kCGImageAlphaNoneSkipLast) {
202       *red = 1;
203       *green = 2;
204       *blue = 3;
205     }
207     if (byteOrder != kCGBitmapByteOrder32Host) {
208       int lastChannel = (CGImageGetBitsPerPixel(cgImage) == 24) ? 2 : 3;
209       *red = lastChannel - *red;
210       *green = lastChannel - *green;
211       *blue = lastChannel - *blue;
212     }
213   }
215   const char* GetPixelData(CGImageRef cgImage) {
216     CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
217     return reinterpret_cast<const char*>(CFDataGetBytePtr(data));
218   }
220   web::TestWebThreadBundle thread_bundle_;
221   base::scoped_nsobject<SnapshotCache> snapshotCache_;
222   base::scoped_nsobject<NSMutableArray> testSessions_;
223   base::scoped_nsobject<NSMutableArray> testImages_;
226 // This test simply put all the snapshots in the cache and then gets them back
227 // As the snapshots are kept in memory, the same pointer can be retrieved.
228 // This test also checks that images are correctly removed from the disk.
229 TEST_F(SnapshotCacheTest, Cache) {
230   // Don't run on tablets because color snapshots are not cached so this test
231   // can't compare the UIImage pointers directly.
232   if (IsIPadIdiom()) {
233     return;
234   }
236   SnapshotCache* cache = GetSnapshotCache();
238   // Put all images in the cache.
239   for (NSUInteger i = 0; i < kSessionCount; ++i) {
240     UIImage* image = [testImages_ objectAtIndex:i];
241     NSString* sessionID = [testSessions_ objectAtIndex:i];
242     [cache setImage:image withSessionID:sessionID];
243   }
245   // Get images back.
246   __block NSUInteger numberOfCallbacks = 0;
247   for (NSUInteger i = 0; i < kSessionCount; ++i) {
248     NSString* sessionID = [testSessions_ objectAtIndex:i];
249     UIImage* expectedImage = [testImages_ objectAtIndex:i];
250     EXPECT_TRUE(expectedImage != nil);
251     [cache retrieveImageForSessionID:sessionID
252                             callback:^(UIImage* image) {
253                               // Images have not been removed from the
254                               // dictionnary. We expect the same pointer.
255                               EXPECT_EQ(expectedImage, image);
256                               ++numberOfCallbacks;
257                             }];
258   }
259   EXPECT_EQ(kSessionCount, numberOfCallbacks);
262 // This test puts all the snapshots in the cache and flushes them to disk.
263 // The snapshots are then reloaded from the disk, and the colors are compared.
264 TEST_F(SnapshotCacheTest, SaveToDisk) {
265   SnapshotCache* cache = GetSnapshotCache();
267   // Put all images in the cache.
268   for (NSUInteger i = 0; i < kSessionCount; ++i) {
269     UIImage* image = [testImages_ objectAtIndex:i];
270     NSString* sessionID = [testSessions_ objectAtIndex:i];
271     [cache setImage:image withSessionID:sessionID];
272   }
273   FlushRunLoops();
275   for (NSUInteger i = 0; i < kSessionCount; ++i) {
276     // Check that images are on the disk.
277     NSString* sessionID = [testSessions_ objectAtIndex:i];
279     base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]);
280     EXPECT_TRUE(base::PathExists(path));
282     // Check image colors by comparing the first pixel against the reference
283     // image.
284     UIImage* image =
285         [UIImage imageWithContentsOfFile:base::SysUTF8ToNSString(path.value())];
286     CGImageRef cgImage = [image CGImage];
287     const char* pixels = GetPixelData(cgImage);
288     EXPECT_TRUE(pixels);
290     UIImage* referenceImage = [testImages_ objectAtIndex:i];
291     CGImageRef referenceCgImage = [referenceImage CGImage];
292     const char* referencePixels = GetPixelData(referenceCgImage);
293     EXPECT_TRUE(referencePixels);
295     if (pixels != nil && referencePixels != nil) {
296       // Color components may not be in the same order,
297       // because of writing to disk and reloading.
298       int red, green, blue;
299       ComputeColorComponents(cgImage, &red, &green, &blue);
301       int referenceRed, referenceGreen, referenceBlue;
302       ComputeColorComponents(referenceCgImage, &referenceRed, &referenceGreen,
303                              &referenceBlue);
305       // Colors may not be exactly the same (compression or rounding errors)
306       // thus a small difference is allowed.
307       EXPECT_NEAR(referencePixels[referenceRed], pixels[red], 1);
308       EXPECT_NEAR(referencePixels[referenceGreen], pixels[green], 1);
309       EXPECT_NEAR(referencePixels[referenceBlue], pixels[blue], 1);
310     }
311   }
314 TEST_F(SnapshotCacheTest, Purge) {
315   SnapshotCache* cache = GetSnapshotCache();
317   // Put all images in the cache.
318   for (NSUInteger i = 0; i < kSessionCount; ++i) {
319     UIImage* image = [testImages_ objectAtIndex:i];
320     NSString* sessionID = [testSessions_ objectAtIndex:i];
321     [cache setImage:image withSessionID:sessionID];
322   }
324   NSMutableSet* liveSessions = [NSMutableSet setWithCapacity:1];
325   [liveSessions addObject:[testSessions_ objectAtIndex:0]];
327   // Purge the cache.
328   [cache purgeCacheOlderThan:(base::Time::Now() - base::TimeDelta::FromHours(1))
329                      keeping:liveSessions];
330   FlushRunLoops();
332   // Check that nothing has been deleted.
333   for (NSUInteger i = 0; i < kSessionCount; ++i) {
334     // Check that images are on the disk.
335     NSString* sessionID = [testSessions_ objectAtIndex:i];
337     base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]);
338     EXPECT_TRUE(base::PathExists(path));
339   }
341   // Purge the cache.
342   [cache purgeCacheOlderThan:base::Time::Now() keeping:liveSessions];
343   FlushRunLoops();
345   // Check that the file have been deleted.
346   for (NSUInteger i = 0; i < kSessionCount; ++i) {
347     // Check that images are on the disk.
348     NSString* sessionID = [testSessions_ objectAtIndex:i];
350     base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]);
351     if (i == 0)
352       EXPECT_TRUE(base::PathExists(path));
353     else
354       EXPECT_FALSE(base::PathExists(path));
355   }
358 // Loads the color images into the cache, and pins two of them.  Ensures that
359 // only the two pinned IDs remain in memory after a call to -handleLowMemory.
360 TEST_F(SnapshotCacheTest, HandleLowMemory) {
361 // TODO(droger): This test fails on iPad iOS8 device: http://crbug.com/455209
362 #if !TARGET_IPHONE_SIMULATOR
363   if (IsIPadIdiom() && base::ios::IsRunningOnIOS8OrLater()) {
364     LOG(WARNING) << "Test disabled on iPad iOS8 device.";
365     return;
366   }
367 #endif
369   LoadAllColorImagesIntoCache(true);
371   SnapshotCache* cache = GetSnapshotCache();
373   NSString* firstPinnedID = [testSessions_ objectAtIndex:4];
374   NSString* secondPinnedID = [testSessions_ objectAtIndex:6];
375   NSMutableSet* set = [NSMutableSet set];
376   [set addObject:firstPinnedID];
377   [set addObject:secondPinnedID];
378   cache.pinnedIDs = set;
380   if (!IsIPadIdiom())
381     [cache handleLowMemory];
383   BOOL expectedValue = YES;
384   if (IsIPadIdiom()) {
385     expectedValue = NO;
386   }
387   EXPECT_EQ(expectedValue, [cache hasImageInMemory:firstPinnedID]);
388   EXPECT_EQ(expectedValue, [cache hasImageInMemory:secondPinnedID]);
390   NSString* notPinnedID = [testSessions_ objectAtIndex:2];
391   EXPECT_FALSE([cache hasImageInMemory:notPinnedID]);
393   // Wait for the final image to be pulled off disk.
394   FlushRunLoops();
397 // Tests that createGreyCache creates the grey snapshots in the background,
398 // from color images in the in-memory cache.  When the grey images are all
399 // loaded into memory, tests that the request to retrieve the grey snapshot
400 // calls the callback immediately.
401 // Disabled on simulators because it sometimes crashes. crbug/421425
402 #if !TARGET_IPHONE_SIMULATOR
403 TEST_F(SnapshotCacheTest, CreateGreyCache) {
404   LoadAllColorImagesIntoCache(true);
406   // Request the creation of a grey image cache for all images.
407   SnapshotCache* cache = GetSnapshotCache();
408   [cache createGreyCache:testSessions_];
410   // Wait for them to be put into the grey image cache.
411   WaitForGreyImagesInCache(kSessionCount);
413   __block NSUInteger numberOfCallbacks = 0;
414   for (NSUInteger i = 0; i < kSessionCount; ++i) {
415     NSString* sessionID = [testSessions_ objectAtIndex:i];
416     [cache retrieveGreyImageForSessionID:sessionID
417                                 callback:^(UIImage* image) {
418                                   EXPECT_TRUE(image);
419                                   ++numberOfCallbacks;
420                                 }];
421   }
423   EXPECT_EQ(numberOfCallbacks, kSessionCount);
426 // Same as previous test, except that all the color images are on disk,
427 // rather than in memory.
428 // Disabled due to the greyImage crash.  b/8048597
429 TEST_F(SnapshotCacheTest, CreateGreyCacheFromDisk) {
430   LoadAllColorImagesIntoCache(true);
432   // Remove color images from in-memory cache.
433   SnapshotCache* cache = GetSnapshotCache();
435   if (!IsIPadIdiom())
436     [cache handleLowMemory];
438   // Request the creation of a grey image cache for all images.
439   [cache createGreyCache:testSessions_];
441   // Wait for them to be put into the grey image cache.
442   WaitForGreyImagesInCache(kSessionCount);
444   __block NSUInteger numberOfCallbacks = 0;
445   for (NSUInteger i = 0; i < kSessionCount; ++i) {
446     NSString* sessionID = [testSessions_ objectAtIndex:i];
447     [cache retrieveGreyImageForSessionID:sessionID
448                                 callback:^(UIImage* image) {
449                                   EXPECT_TRUE(image);
450                                   ++numberOfCallbacks;
451                                 }];
452   }
454   EXPECT_EQ(numberOfCallbacks, kSessionCount);
456 #endif  // !TARGET_IPHONE_SIMULATOR
458 // Tests mostRecentGreyBlock, which is a block to be called when the most
459 // recently requested grey image is finally loaded.
460 // The test requests three images be cached as grey images.  Only the final
461 // callback of the three requests should be called.
462 // Disabled due to the greyImage crash.  b/8048597
463 TEST_F(SnapshotCacheTest, MostRecentGreyBlock) {
464   const NSUInteger kNumImages = 3;
465   base::scoped_nsobject<NSMutableArray> sessionIDs(
466       [[NSMutableArray alloc] initWithCapacity:kNumImages]);
467   [sessionIDs addObject:[testSessions_ objectAtIndex:0]];
468   [sessionIDs addObject:[testSessions_ objectAtIndex:1]];
469   [sessionIDs addObject:[testSessions_ objectAtIndex:2]];
471   SnapshotCache* cache = GetSnapshotCache();
473   // Put 3 images in the cache.
474   LoadColorImagesIntoCache(kNumImages, true);
475   // Make sure the color images are only on disk, to ensure the background
476   // thread is slow enough to queue up the requests.
477   if (!IsIPadIdiom())
478     [cache handleLowMemory];
480   // Enable the grey image cache.
481   [cache createGreyCache:sessionIDs];
483   // Request the grey versions
484   __block BOOL firstCallbackCalled = NO;
485   __block BOOL secondCallbackCalled = NO;
486   __block BOOL thirdCallbackCalled = NO;
487   [cache greyImageForSessionID:[testSessions_ objectAtIndex:0]
488                       callback:^(UIImage*) {
489                         firstCallbackCalled = YES;
490                       }];
491   [cache greyImageForSessionID:[testSessions_ objectAtIndex:1]
492                       callback:^(UIImage*) {
493                         secondCallbackCalled = YES;
494                       }];
495   [cache greyImageForSessionID:[testSessions_ objectAtIndex:2]
496                       callback:^(UIImage*) {
497                         thirdCallbackCalled = YES;
498                       }];
500   // Wait for them to be loaded.
501   WaitForGreyImagesInCache(kNumImages);
503   EXPECT_FALSE(firstCallbackCalled);
504   EXPECT_FALSE(secondCallbackCalled);
505   EXPECT_TRUE(thirdCallbackCalled);
508 // Test the function used to save a grey copy of a color snapshot fully on a
509 // background thread when the application is backgrounded.
510 // Disabled due to the greyImage crash.  b/8048597
511 TEST_F(SnapshotCacheTest, GreyImageAllInBackground) {
512   LoadAllColorImagesIntoCache(true);
514   SnapshotCache* cache = GetSnapshotCache();
516   // Now convert every image into a grey image, on disk, in the background.
517   for (NSUInteger i = 0; i < kSessionCount; ++i) {
518     [cache saveGreyInBackgroundForSessionID:[testSessions_ objectAtIndex:i]];
519   }
521   // Waits for the grey images for the sessions in |testSessions_| to be written
522   // to disk, which happens in a background thread.
523   FlushRunLoops();
525   for (NSString* sessionID in testSessions_.get()) {
526     base::FilePath path([SnapshotCache greyImagePathForSessionID:sessionID]);
527     EXPECT_TRUE(base::PathExists(path));
528     base::DeleteFile(path, false);
529   }
532 // Verifies that image size and scale are preserved when writing and reading
533 // from disk.
534 TEST_F(SnapshotCacheTest, SizeAndScalePreservation) {
535   // Create an image with the expected snapshot scale.
536   CGFloat scale = [SnapshotCache snapshotScaleForDevice];
537   UIGraphicsBeginImageContextWithOptions(
538       CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, scale);
539   CGContextRef context = UIGraphicsGetCurrentContext();
540   UIImage* image = GenerateRandomImage(context);
541   UIGraphicsEndImageContext();
543   // Add the image to the cache then call handle low memory to ensure the image
544   // is read from disk instead of the in-memory cache.
545   SnapshotCache* cache = GetSnapshotCache();
546   NSString* const kSession = @"foo";
547   [cache setImage:image withSessionID:kSession];
548   FlushRunLoops();  // ensure the file is written to disk.
549   if (!IsIPadIdiom())
550     [cache handleLowMemory];
552   // Retrive the image and have the callback verify the size and scale.
553   __block BOOL callbackComplete = NO;
554   [cache retrieveImageForSessionID:kSession
555                           callback:^(UIImage* imageFromDisk) {
556                             EXPECT_EQ(image.size.width,
557                                       imageFromDisk.size.width);
558                             EXPECT_EQ(image.size.height,
559                                       imageFromDisk.size.height);
560                             EXPECT_EQ(image.scale, imageFromDisk.scale);
561                             callbackComplete = YES;
562                           }];
563   FlushRunLoops();
564   EXPECT_TRUE(callbackComplete);
567 // Verifies that retina-scale images are deleted properly.
568 TEST_F(SnapshotCacheTest, DeleteRetinaImages) {
569   if ([SnapshotCache snapshotScaleForDevice] != 2.0) {
570     return;
571   }
573   // Create an image with retina scale.
574   UIGraphicsBeginImageContextWithOptions(
575       CGSizeMake(kSnapshotPixelSize, kSnapshotPixelSize), NO, 2.0);
576   CGContextRef context = UIGraphicsGetCurrentContext();
577   UIImage* image = GenerateRandomImage(context);
578   UIGraphicsEndImageContext();
580   // Add the image to the cache then call handle low memory to ensure the image
581   // is read from disk instead of the in-memory cache.
582   SnapshotCache* cache = GetSnapshotCache();
583   NSString* const kSession = @"foo";
584   [cache setImage:image withSessionID:kSession];
585   FlushRunLoops();  // ensure the file is written to disk.
586   if (!IsIPadIdiom())
587     [cache handleLowMemory];
589   // Verify the file was writted with @2x in the file name.
590   base::FilePath retinaFile = [SnapshotCache imagePathForSessionID:kSession];
591   EXPECT_TRUE(base::PathExists(retinaFile));
593   // Delete the image.
594   [cache removeImageWithSessionID:kSession];
595   FlushRunLoops();  // ensure the file is removed.
597   EXPECT_FALSE(base::PathExists(retinaFile));
600 }  // namespace