| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" | 5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" |
| 6 | 6 |
| 7 #import <Foundation/Foundation.h> | 7 #import <Foundation/Foundation.h> |
| 8 | 8 |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 12 #include "base/ios/ios_util.h" | |
| 13 #include "base/location.h" | 12 #include "base/location.h" |
| 14 #include "base/mac/bind_objc_block.h" | 13 #include "base/mac/bind_objc_block.h" |
| 15 #include "base/mac/scoped_nsautorelease_pool.h" | 14 #include "base/mac/scoped_nsautorelease_pool.h" |
| 16 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 16 #include "base/strings/sys_string_conversions.h" |
| 18 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 19 #include "ios/chrome/browser/experimental_flags.h" | 18 #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h" |
| 20 #include "ios/chrome/browser/ui/ui_util.h" | |
| 21 #include "ios/web/public/test/test_web_thread_bundle.h" | 19 #include "ios/web/public/test/test_web_thread_bundle.h" |
| 22 #include "ios/web/public/web_thread.h" | 20 #include "ios/web/public/web_thread.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 24 #include "testing/gtest_mac.h" | 22 #include "testing/gtest_mac.h" |
| 25 #include "testing/platform_test.h" | 23 #include "testing/platform_test.h" |
| 26 | 24 |
| 27 static const NSUInteger kSessionCount = 10; | 25 static const NSUInteger kSessionCount = 10; |
| 28 static const NSUInteger kSnapshotPixelSize = 8; | 26 static const NSUInteger kSnapshotPixelSize = 8; |
| 29 | 27 |
| 30 // Promote some implementation methods to public. | |
| 31 @interface SnapshotCache (Testing) | |
| 32 + (base::FilePath)imagePathForSessionID:(NSString*)sessionID; | |
| 33 + (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID; | |
| 34 - (void)handleLowMemory; | |
| 35 @end | |
| 36 | |
| 37 namespace { | 28 namespace { |
| 38 | 29 |
| 39 class SnapshotCacheTest : public PlatformTest { | 30 class SnapshotCacheTest : public PlatformTest { |
| 40 protected: | 31 protected: |
| 41 // Build an array of session names and an array of UIImages filled with | 32 // Build an array of session names and an array of UIImages filled with |
| 42 // random colors. | 33 // random colors. |
| 43 void SetUp() override { | 34 void SetUp() override { |
| 44 PlatformTest::SetUp(); | 35 PlatformTest::SetUp(); |
| 45 snapshotCache_.reset([[SnapshotCache alloc] init]); | 36 snapshotCache_.reset([[SnapshotCache alloc] init]); |
| 46 testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]); | 37 testImages_.reset([[NSMutableArray alloc] initWithCapacity:kSessionCount]); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 *green = lastChannel - *green; | 188 *green = lastChannel - *green; |
| 198 *blue = lastChannel - *blue; | 189 *blue = lastChannel - *blue; |
| 199 } | 190 } |
| 200 } | 191 } |
| 201 | 192 |
| 202 const char* GetPixelData(CGImageRef cgImage) { | 193 const char* GetPixelData(CGImageRef cgImage) { |
| 203 CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); | 194 CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); |
| 204 return reinterpret_cast<const char*>(CFDataGetBytePtr(data)); | 195 return reinterpret_cast<const char*>(CFDataGetBytePtr(data)); |
| 205 } | 196 } |
| 206 | 197 |
| 198 void TriggerMemoryWarning() { |
| 199 // _performMemoryWarning is a private API and must not be compiled into |
| 200 // official builds. |
| 201 [[UIApplication sharedApplication] |
| 202 performSelector:@selector(_performMemoryWarning)]; |
| 203 } |
| 204 |
| 207 web::TestWebThreadBundle thread_bundle_; | 205 web::TestWebThreadBundle thread_bundle_; |
| 208 base::scoped_nsobject<SnapshotCache> snapshotCache_; | 206 base::scoped_nsobject<SnapshotCache> snapshotCache_; |
| 209 base::scoped_nsobject<NSMutableArray> testSessions_; | 207 base::scoped_nsobject<NSMutableArray> testSessions_; |
| 210 base::scoped_nsobject<NSMutableArray> testImages_; | 208 base::scoped_nsobject<NSMutableArray> testImages_; |
| 211 }; | 209 }; |
| 212 | 210 |
| 213 // This test simply put all the snapshots in the cache and then gets them back | 211 // This test simply put all the snapshots in the cache and then gets them back |
| 214 // As the snapshots are kept in memory, the same pointer can be retrieved. | 212 // As the snapshots are kept in memory, the same pointer can be retrieved. |
| 215 // This test also checks that images are correctly removed from the disk. | 213 // This test also checks that images are correctly removed from the disk. |
| 216 TEST_F(SnapshotCacheTest, Cache) { | 214 TEST_F(SnapshotCacheTest, Cache) { |
| 217 // Don't run on tablets because color snapshots are not cached so this test | |
| 218 // can't compare the UIImage pointers directly. | |
| 219 if (IsIPadIdiom() && !experimental_flags::IsTabSwitcherEnabled()) { | |
| 220 return; | |
| 221 } | |
| 222 | |
| 223 SnapshotCache* cache = GetSnapshotCache(); | 215 SnapshotCache* cache = GetSnapshotCache(); |
| 224 | 216 |
| 217 if (![cache inMemoryCacheIsEnabled]) |
| 218 return; |
| 219 |
| 225 NSUInteger expectedCacheSize = kSessionCount; | 220 NSUInteger expectedCacheSize = kSessionCount; |
| 226 if (experimental_flags::IsLRUSnapshotCacheEnabled()) | 221 if ([cache usesLRUCache]) |
| 227 expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); | 222 expectedCacheSize = MIN(kSessionCount, [cache lruCacheMaxSize]); |
| 228 | 223 |
| 229 // Put all images in the cache. | 224 // Put all images in the cache. |
| 230 for (NSUInteger i = 0; i < expectedCacheSize; ++i) { | 225 for (NSUInteger i = 0; i < expectedCacheSize; ++i) { |
| 231 UIImage* image = [testImages_ objectAtIndex:i]; | 226 UIImage* image = [testImages_ objectAtIndex:i]; |
| 232 NSString* sessionID = [testSessions_ objectAtIndex:i]; | 227 NSString* sessionID = [testSessions_ objectAtIndex:i]; |
| 233 [cache setImage:image withSessionID:sessionID]; | 228 [cache setImage:image withSessionID:sessionID]; |
| 234 } | 229 } |
| 235 | 230 |
| 236 // Get images back. | 231 // Get images back. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 | 335 |
| 341 base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); | 336 base::FilePath path([SnapshotCache imagePathForSessionID:sessionID]); |
| 342 if (i == 0) | 337 if (i == 0) |
| 343 EXPECT_TRUE(base::PathExists(path)); | 338 EXPECT_TRUE(base::PathExists(path)); |
| 344 else | 339 else |
| 345 EXPECT_FALSE(base::PathExists(path)); | 340 EXPECT_FALSE(base::PathExists(path)); |
| 346 } | 341 } |
| 347 } | 342 } |
| 348 | 343 |
| 349 // Loads the color images into the cache, and pins two of them. Ensures that | 344 // Loads the color images into the cache, and pins two of them. Ensures that |
| 350 // only the two pinned IDs remain in memory after a call to -handleLowMemory. | 345 // only the two pinned IDs remain in memory after a memory warning. |
| 351 TEST_F(SnapshotCacheTest, HandleLowMemory) { | 346 TEST_F(SnapshotCacheTest, HandleMemoryWarning) { |
| 352 // TODO(crbug.com/455209): This test failed on iPad iOS8 device, but may no | |
| 353 // longer be failing on iOS 9 and up. Should test by re-enabling and monitor. | |
| 354 #if !TARGET_IPHONE_SIMULATOR | |
| 355 if (IsIPadIdiom()) { | |
| 356 LOG(WARNING) << "Test disabled on iPad device."; | |
| 357 return; | |
| 358 } | |
| 359 #endif | |
| 360 | |
| 361 LoadAllColorImagesIntoCache(true); | 347 LoadAllColorImagesIntoCache(true); |
| 362 | 348 |
| 363 SnapshotCache* cache = GetSnapshotCache(); | 349 SnapshotCache* cache = GetSnapshotCache(); |
| 364 | 350 |
| 365 NSString* firstPinnedID = [testSessions_ objectAtIndex:4]; | 351 NSString* firstPinnedID = [testSessions_ objectAtIndex:4]; |
| 366 NSString* secondPinnedID = [testSessions_ objectAtIndex:6]; | 352 NSString* secondPinnedID = [testSessions_ objectAtIndex:6]; |
| 367 NSMutableSet* set = [NSMutableSet set]; | 353 NSMutableSet* set = [NSMutableSet set]; |
| 368 [set addObject:firstPinnedID]; | 354 [set addObject:firstPinnedID]; |
| 369 [set addObject:secondPinnedID]; | 355 [set addObject:secondPinnedID]; |
| 370 cache.pinnedIDs = set; | 356 cache.pinnedIDs = set; |
| 371 | 357 |
| 372 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) | 358 TriggerMemoryWarning(); |
| 373 [cache handleLowMemory]; | |
| 374 | 359 |
| 375 BOOL expectedValue = YES; | 360 if ([cache inMemoryCacheIsEnabled]) { |
| 376 if (IsIPadIdiom() && !experimental_flags::IsTabSwitcherEnabled()) | 361 EXPECT_EQ(YES, [cache hasImageInMemory:firstPinnedID]); |
| 377 expectedValue = NO; | 362 EXPECT_EQ(YES, [cache hasImageInMemory:secondPinnedID]); |
| 378 | 363 } else { |
| 379 EXPECT_EQ(expectedValue, [cache hasImageInMemory:firstPinnedID]); | 364 EXPECT_EQ(NO, [cache hasImageInMemory:firstPinnedID]); |
| 380 EXPECT_EQ(expectedValue, [cache hasImageInMemory:secondPinnedID]); | 365 EXPECT_EQ(NO, [cache hasImageInMemory:secondPinnedID]); |
| 366 } |
| 381 | 367 |
| 382 NSString* notPinnedID = [testSessions_ objectAtIndex:2]; | 368 NSString* notPinnedID = [testSessions_ objectAtIndex:2]; |
| 383 EXPECT_FALSE([cache hasImageInMemory:notPinnedID]); | 369 EXPECT_FALSE([cache hasImageInMemory:notPinnedID]); |
| 384 | 370 |
| 385 // Wait for the final image to be pulled off disk. | 371 // Wait for the final image to be pulled off disk. |
| 386 FlushRunLoops(); | 372 FlushRunLoops(); |
| 387 } | 373 } |
| 388 | 374 |
| 389 // Tests that createGreyCache creates the grey snapshots in the background, | 375 // Tests that createGreyCache creates the grey snapshots in the background, |
| 390 // from color images in the in-memory cache. When the grey images are all | 376 // from color images in the in-memory cache. When the grey images are all |
| (...skipping 26 matching lines...) Expand all Loading... |
| 417 | 403 |
| 418 // Same as previous test, except that all the color images are on disk, | 404 // Same as previous test, except that all the color images are on disk, |
| 419 // rather than in memory. | 405 // rather than in memory. |
| 420 // Disabled due to the greyImage crash. b/8048597 | 406 // Disabled due to the greyImage crash. b/8048597 |
| 421 TEST_F(SnapshotCacheTest, CreateGreyCacheFromDisk) { | 407 TEST_F(SnapshotCacheTest, CreateGreyCacheFromDisk) { |
| 422 LoadAllColorImagesIntoCache(true); | 408 LoadAllColorImagesIntoCache(true); |
| 423 | 409 |
| 424 // Remove color images from in-memory cache. | 410 // Remove color images from in-memory cache. |
| 425 SnapshotCache* cache = GetSnapshotCache(); | 411 SnapshotCache* cache = GetSnapshotCache(); |
| 426 | 412 |
| 427 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) | 413 TriggerMemoryWarning(); |
| 428 [cache handleLowMemory]; | |
| 429 | 414 |
| 430 // Request the creation of a grey image cache for all images. | 415 // Request the creation of a grey image cache for all images. |
| 431 [cache createGreyCache:testSessions_]; | 416 [cache createGreyCache:testSessions_]; |
| 432 | 417 |
| 433 // Wait for them to be put into the grey image cache. | 418 // Wait for them to be put into the grey image cache. |
| 434 WaitForGreyImagesInCache(kSessionCount); | 419 WaitForGreyImagesInCache(kSessionCount); |
| 435 | 420 |
| 436 __block NSUInteger numberOfCallbacks = 0; | 421 __block NSUInteger numberOfCallbacks = 0; |
| 437 for (NSUInteger i = 0; i < kSessionCount; ++i) { | 422 for (NSUInteger i = 0; i < kSessionCount; ++i) { |
| 438 NSString* sessionID = [testSessions_ objectAtIndex:i]; | 423 NSString* sessionID = [testSessions_ objectAtIndex:i]; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 459 [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; | 444 [sessionIDs addObject:[testSessions_ objectAtIndex:0]]; |
| 460 [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; | 445 [sessionIDs addObject:[testSessions_ objectAtIndex:1]]; |
| 461 [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; | 446 [sessionIDs addObject:[testSessions_ objectAtIndex:2]]; |
| 462 | 447 |
| 463 SnapshotCache* cache = GetSnapshotCache(); | 448 SnapshotCache* cache = GetSnapshotCache(); |
| 464 | 449 |
| 465 // Put 3 images in the cache. | 450 // Put 3 images in the cache. |
| 466 LoadColorImagesIntoCache(kNumImages, true); | 451 LoadColorImagesIntoCache(kNumImages, true); |
| 467 // Make sure the color images are only on disk, to ensure the background | 452 // Make sure the color images are only on disk, to ensure the background |
| 468 // thread is slow enough to queue up the requests. | 453 // thread is slow enough to queue up the requests. |
| 469 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) | 454 TriggerMemoryWarning(); |
| 470 [cache handleLowMemory]; | |
| 471 | 455 |
| 472 // Enable the grey image cache. | 456 // Enable the grey image cache. |
| 473 [cache createGreyCache:sessionIDs]; | 457 [cache createGreyCache:sessionIDs]; |
| 474 | 458 |
| 475 // Request the grey versions | 459 // Request the grey versions |
| 476 __block BOOL firstCallbackCalled = NO; | 460 __block BOOL firstCallbackCalled = NO; |
| 477 __block BOOL secondCallbackCalled = NO; | 461 __block BOOL secondCallbackCalled = NO; |
| 478 __block BOOL thirdCallbackCalled = NO; | 462 __block BOOL thirdCallbackCalled = NO; |
| 479 [cache greyImageForSessionID:[testSessions_ objectAtIndex:0] | 463 [cache greyImageForSessionID:[testSessions_ objectAtIndex:0] |
| 480 callback:^(UIImage*) { | 464 callback:^(UIImage*) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 CGContextRef context = UIGraphicsGetCurrentContext(); | 515 CGContextRef context = UIGraphicsGetCurrentContext(); |
| 532 UIImage* image = GenerateRandomImage(context); | 516 UIImage* image = GenerateRandomImage(context); |
| 533 UIGraphicsEndImageContext(); | 517 UIGraphicsEndImageContext(); |
| 534 | 518 |
| 535 // Add the image to the cache then call handle low memory to ensure the image | 519 // Add the image to the cache then call handle low memory to ensure the image |
| 536 // is read from disk instead of the in-memory cache. | 520 // is read from disk instead of the in-memory cache. |
| 537 SnapshotCache* cache = GetSnapshotCache(); | 521 SnapshotCache* cache = GetSnapshotCache(); |
| 538 NSString* const kSession = @"foo"; | 522 NSString* const kSession = @"foo"; |
| 539 [cache setImage:image withSessionID:kSession]; | 523 [cache setImage:image withSessionID:kSession]; |
| 540 FlushRunLoops(); // ensure the file is written to disk. | 524 FlushRunLoops(); // ensure the file is written to disk. |
| 541 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) | 525 TriggerMemoryWarning(); |
| 542 [cache handleLowMemory]; | |
| 543 | 526 |
| 544 // Retrive the image and have the callback verify the size and scale. | 527 // Retrive the image and have the callback verify the size and scale. |
| 545 __block BOOL callbackComplete = NO; | 528 __block BOOL callbackComplete = NO; |
| 546 [cache retrieveImageForSessionID:kSession | 529 [cache retrieveImageForSessionID:kSession |
| 547 callback:^(UIImage* imageFromDisk) { | 530 callback:^(UIImage* imageFromDisk) { |
| 548 EXPECT_EQ(image.size.width, | 531 EXPECT_EQ(image.size.width, |
| 549 imageFromDisk.size.width); | 532 imageFromDisk.size.width); |
| 550 EXPECT_EQ(image.size.height, | 533 EXPECT_EQ(image.size.height, |
| 551 imageFromDisk.size.height); | 534 imageFromDisk.size.height); |
| 552 EXPECT_EQ(image.scale, imageFromDisk.scale); | 535 EXPECT_EQ(image.scale, imageFromDisk.scale); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 568 CGContextRef context = UIGraphicsGetCurrentContext(); | 551 CGContextRef context = UIGraphicsGetCurrentContext(); |
| 569 UIImage* image = GenerateRandomImage(context); | 552 UIImage* image = GenerateRandomImage(context); |
| 570 UIGraphicsEndImageContext(); | 553 UIGraphicsEndImageContext(); |
| 571 | 554 |
| 572 // Add the image to the cache then call handle low memory to ensure the image | 555 // Add the image to the cache then call handle low memory to ensure the image |
| 573 // is read from disk instead of the in-memory cache. | 556 // is read from disk instead of the in-memory cache. |
| 574 SnapshotCache* cache = GetSnapshotCache(); | 557 SnapshotCache* cache = GetSnapshotCache(); |
| 575 NSString* const kSession = @"foo"; | 558 NSString* const kSession = @"foo"; |
| 576 [cache setImage:image withSessionID:kSession]; | 559 [cache setImage:image withSessionID:kSession]; |
| 577 FlushRunLoops(); // ensure the file is written to disk. | 560 FlushRunLoops(); // ensure the file is written to disk. |
| 578 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) | 561 TriggerMemoryWarning(); |
| 579 [cache handleLowMemory]; | |
| 580 | 562 |
| 581 // Verify the file was writted with @2x in the file name. | 563 // Verify the file was writted with @2x in the file name. |
| 582 base::FilePath retinaFile = [SnapshotCache imagePathForSessionID:kSession]; | 564 base::FilePath retinaFile = [SnapshotCache imagePathForSessionID:kSession]; |
| 583 EXPECT_TRUE(base::PathExists(retinaFile)); | 565 EXPECT_TRUE(base::PathExists(retinaFile)); |
| 584 | 566 |
| 585 // Delete the image. | 567 // Delete the image. |
| 586 [cache removeImageWithSessionID:kSession]; | 568 [cache removeImageWithSessionID:kSession]; |
| 587 FlushRunLoops(); // ensure the file is removed. | 569 FlushRunLoops(); // ensure the file is removed. |
| 588 | 570 |
| 589 EXPECT_FALSE(base::PathExists(retinaFile)); | 571 EXPECT_FALSE(base::PathExists(retinaFile)); |
| 590 } | 572 } |
| 591 | 573 |
| 592 } // namespace | 574 } // namespace |
| OLD | NEW |