Index: ios/chrome/browser/web/cache_egtest.mm |
diff --git a/ios/chrome/browser/web/cache_egtest.mm b/ios/chrome/browser/web/cache_egtest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6c0e27f9369613eb39da93124a1bcc836136d3c1 |
--- /dev/null |
+++ b/ios/chrome/browser/web/cache_egtest.mm |
@@ -0,0 +1,288 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import <EarlGrey/EarlGrey.h> |
+ |
+#import "base/mac/scoped_nsobject.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/strings/stringprintf.h" |
+#include "components/content_settings/core/browser/host_content_settings_map.h" |
+#include "components/content_settings/core/common/content_settings.h" |
+#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" |
+#import "ios/chrome/browser/ui/commands/generic_chrome_command.h" |
+#include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
+#import "ios/chrome/test/app/chrome_test_util.h" |
+#include "ios/chrome/test/app/history_test_util.h" |
+#include "ios/chrome/test/app/navigation_test_util.h" |
+#include "ios/chrome/test/app/web_view_interaction_test_util.h" |
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" |
+#import "ios/chrome/test/earl_grey/chrome_matchers.h" |
+#import "ios/chrome/test/earl_grey/chrome_test_case.h" |
+#import "ios/testing/wait_util.h" |
+#import "ios/web/public/test/http_server.h" |
+#include "ios/web/public/test/http_server_util.h" |
+#include "ios/web/public/test/response_providers/html_response_provider.h" |
+#include "url/gurl.h" |
+ |
+using chrome_test_util::webViewContainingText; |
+using web::test::HttpServer; |
+ |
+namespace { |
+ |
+// First page for cache testing. |
+const char kCacheTestFirstPageURL[] = "http://cacheTestFirstPage"; |
+ |
+// Second page for cache testing. |
+const char kCacheTestSecondPageURL[] = "http://cacheTestSecondPage"; |
+ |
+// Third page for cache testing. |
+const char kCacheTestThirdPageURL[] = "http://cacheTestThirdPage"; |
+ |
+// ID for HTML hyperlink element. |
+const char kCacheTestLinkID[] = "cache-test-link-id"; |
+ |
+// Response provider for cache testing that provides server hit count and |
+// cache-control request header. |
+class CacheTestResponseProvider : public web::DataResponseProvider { |
+ public: |
+ CacheTestResponseProvider() |
+ : first_page_url_(HttpServer::MakeUrl(kCacheTestFirstPageURL)), |
+ second_page_url_(HttpServer::MakeUrl(kCacheTestSecondPageURL)), |
+ third_page_url_(HttpServer::MakeUrl(kCacheTestThirdPageURL)) {} |
+ ~CacheTestResponseProvider() override {} |
+ |
+ // HtmlResponseProvider overrides: |
+ bool CanHandleRequest(const Request& request) override { |
+ return request.url == first_page_url_ || request.url == second_page_url_ || |
+ request.url == third_page_url_; |
+ } |
+ void GetResponseHeadersAndBody( |
+ const Request& request, |
+ scoped_refptr<net::HttpResponseHeaders>* headers, |
+ std::string* response_body) override { |
+ hit_counter_++; |
+ std::string cache_control_header; |
+ if (request.headers.HasHeader("Cache-Control")) { |
+ request.headers.GetHeader("Cache-Control", &cache_control_header); |
+ } |
+ *headers = web::ResponseProvider::GetDefaultResponseHeaders(); |
+ |
+ if (request.url == first_page_url_) { |
+ *response_body = base::StringPrintf( |
+ "<p>First Page</p>" |
+ "<p>serverHitCounter: %d</p>" |
+ "<p>cacheControl: %s</p>" |
+ "<a href='%s' id='%s'>link to second page</a>", |
+ hit_counter_, cache_control_header.c_str(), |
+ second_page_url_.spec().c_str(), kCacheTestLinkID); |
+ |
+ } else if (request.url == second_page_url_) { |
+ *response_body = base::StringPrintf( |
+ "<p>Second Page</p>" |
+ "<p>serverHitCounter: %d</p>" |
+ "<p>cacheControl: %s</p>", |
+ hit_counter_, cache_control_header.c_str()); |
+ } else if (request.url == third_page_url_) { |
+ *response_body = base::StringPrintf( |
+ "<p>Third Page</p>" |
+ "<p>serverHitCounter: %d</p>" |
+ "<p>cacheControl: %s</p>" |
+ "<a href='%s' id='%s' target='_blank'>" |
+ "link to first page in new tab</a>", |
+ hit_counter_, cache_control_header.c_str(), |
+ first_page_url_.spec().c_str(), kCacheTestLinkID); |
+ } else { |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ private: |
+ // A number that counts requests that have reached the server. |
+ int hit_counter_ = 0; |
+ |
+ // URLs for three test pages. |
+ GURL first_page_url_; |
+ GURL second_page_url_; |
+ GURL third_page_url_; |
+}; |
+ |
+// ScopedBlockPopupsPref modifies the block popups preference and resets the |
+// preference to its original value when this object goes out of scope. |
+// TODO(crbug.com/638674): Evaluate if this can move to shared code. |
+class ScopedBlockPopupsPref { |
+ public: |
+ explicit ScopedBlockPopupsPref(ContentSetting setting) { |
+ original_setting_ = GetPrefValue(); |
+ SetPrefValue(setting); |
+ } |
+ ~ScopedBlockPopupsPref() { SetPrefValue(original_setting_); } |
+ |
+ private: |
+ // Gets the current value of the preference. |
+ ContentSetting GetPrefValue() { |
+ ContentSetting popupSetting = |
+ ios::HostContentSettingsMapFactory::GetForBrowserState( |
+ chrome_test_util::GetOriginalBrowserState()) |
+ ->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS, NULL); |
+ return popupSetting; |
+ } |
+ |
+ // Sets the preference to the given value. |
+ void SetPrefValue(ContentSetting setting) { |
+ DCHECK(setting == CONTENT_SETTING_BLOCK || |
+ setting == CONTENT_SETTING_ALLOW); |
+ ios::ChromeBrowserState* state = |
+ chrome_test_util::GetOriginalBrowserState(); |
+ ios::HostContentSettingsMapFactory::GetForBrowserState(state) |
+ ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS, setting); |
+ } |
+ |
+ // Saves the original pref setting so that it can be restored when the scoper |
+ // is destroyed. |
+ ContentSetting original_setting_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScopedBlockPopupsPref); |
+}; |
+ |
+} // namespace |
+ |
+// Tests the browser cache behavior when navigating to cached pages. |
+@interface CacheTestCase : ChromeTestCase |
+@end |
+ |
+@implementation CacheTestCase |
+ |
+// Reloads the web view and waits for the loading to complete. |
+// TODO(crbug.com/638674): Evaluate if this can move to shared code |
+- (void)reloadPage { |
+ base::scoped_nsobject<GenericChromeCommand> reloadCommand( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_RELOAD]); |
+ chrome_test_util::RunCommandWithActiveViewController(reloadCommand); |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+} |
+ |
+// Navigates back to the previous webpage. |
+// TODO(crbug.com/638674): Evaluate if this can move to shared code. |
+- (void)goBack { |
+ base::scoped_nsobject<GenericChromeCommand> backCommand( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_BACK]); |
+ chrome_test_util::RunCommandWithActiveViewController(backCommand); |
+ |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+} |
+ |
+// Tests caching behavior on navigate back and page reload. Navigate back should |
+// use the cached page. Page reload should use cache-control in the request |
+// header and show updated page. |
+- (void)testCachingBehaviorOnNavigateBackAndPageReload { |
+ web::test::SetUpHttpServer(base::MakeUnique<CacheTestResponseProvider>()); |
+ |
+ const GURL cacheTestFirstPageURL = |
+ HttpServer::MakeUrl(kCacheTestFirstPageURL); |
+ |
+ // 1st hit to server. Verify that the server has the correct hit count. |
+ [ChromeEarlGrey loadURL:cacheTestFirstPageURL]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 1")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Navigate to another page. 2nd hit to server. |
+ chrome_test_util::TapWebViewElementWithId(kCacheTestLinkID); |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 2")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Navigate back. This should not hit the server. Verify the page has been |
+ // loaded from cache. The serverHitCounter will remain the same. |
+ [self goBack]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 1")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Reload page. 3rd hit to server. Verify that page reload causes the |
+ // hitCounter to show updated value. |
+ [self reloadPage]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 3")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Verify that page reload causes Cache-Control value to be sent with request. |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("cacheControl: max-age=0")] |
+ assertWithMatcher:grey_notNil()]; |
+} |
+ |
+// Tests caching behavior when opening new tab. New tab should not use the |
+// cached page. |
+// TODO(crbug.com/644646): Monitor this test for flakiness. |
+- (void)testCachingBehaviorOnOpenNewTab { |
+ web::test::SetUpHttpServer(base::MakeUnique<CacheTestResponseProvider>()); |
+ |
+ const GURL cacheTestFirstPageURL = |
+ HttpServer::MakeUrl(kCacheTestFirstPageURL); |
+ const GURL cacheTestThirdPageURL = |
+ HttpServer::MakeUrl(kCacheTestThirdPageURL); |
+ |
+ // 1st hit to server. Verify title and hitCount. |
+ [ChromeEarlGrey loadURL:cacheTestFirstPageURL]; |
+ [[EarlGrey selectElementWithMatcher:webViewContainingText("First Page")] |
+ assertWithMatcher:grey_notNil()]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 1")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // 2nd hit to server. Verify hitCount. |
+ [ChromeEarlGrey loadURL:cacheTestThirdPageURL]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 2")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Open the first page in a new tab. Verify that cache was not used. Must |
+ // first allow popups. |
+ ScopedBlockPopupsPref prefSetter(CONTENT_SETTING_ALLOW); |
+ chrome_test_util::TapWebViewElementWithId(kCacheTestLinkID); |
+ [ChromeEarlGrey waitForPageToFinishLoading]; |
+ [[EarlGrey selectElementWithMatcher:webViewContainingText("First Page")] |
+ assertWithMatcher:grey_notNil()]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 3")] |
+ assertWithMatcher:grey_notNil()]; |
+} |
+ |
+// Tests that cache is not used when selecting omnibox suggested website, even |
+// though cache for that website exists. |
+- (void)testCachingBehaviorOnSelectOmniboxSuggestion { |
+ web::test::SetUpHttpServer(base::MakeUnique<CacheTestResponseProvider>()); |
+ |
+ // Clear the history to ensure expected omnibox autocomplete results. |
+ chrome_test_util::ClearBrowsingHistory(); |
+ |
+ const GURL cacheTestFirstPageURL = |
+ HttpServer::MakeUrl(kCacheTestFirstPageURL); |
+ |
+ // 1st hit to server. Verify title and hitCount. |
+ [ChromeEarlGrey loadURL:cacheTestFirstPageURL]; |
+ [[EarlGrey selectElementWithMatcher:webViewContainingText("First Page")] |
+ assertWithMatcher:grey_notNil()]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 1")] |
+ assertWithMatcher:grey_notNil()]; |
+ |
+ // Type a search into omnnibox and select the first suggestion (second row) |
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::omnibox()] |
+ performAction:grey_typeText(@"cachetestfirstpage")]; |
+ [[EarlGrey |
+ selectElementWithMatcher:grey_accessibilityID(@"omnibox suggestion 1")] |
+ performAction:grey_tap()]; |
+ |
+ // Verify title and hitCount. Cache should not be used. |
+ [[EarlGrey selectElementWithMatcher:webViewContainingText("First Page")] |
+ assertWithMatcher:grey_notNil()]; |
+ [[EarlGrey |
+ selectElementWithMatcher:webViewContainingText("serverHitCounter: 2")] |
+ assertWithMatcher:grey_notNil()]; |
+} |
+ |
+@end |