1 // Copyright (c) 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. 4 5 #include "base/bind.h" 6 #include "base/file_util.h" 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/memory/ref_counted.h" 9 #include "base/message_loop/message_loop.h" 10 #include "content/browser/appcache/chrome_appcache_service.h" 11 #include "content/browser/browser_thread_impl.h" 12 #include "content/public/browser/resource_context.h" 13 #include "content/public/test/mock_special_storage_policy.h" 14 #include "content/public/test/test_browser_context.h" 15 #include "content/test/appcache_test_helper.h" 16 #include "net/url_request/url_request_context_getter.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 #include "webkit/browser/appcache/appcache_database.h" 19 #include "webkit/browser/appcache/appcache_storage_impl.h" 20 21 #include <set> 22 23 namespace content { 24 namespace { 25 const base::FilePath::CharType kTestingAppCacheDirname[] = 26 FILE_PATH_LITERAL("Application Cache"); 27 28 // Examples of a protected and an unprotected origin, to be used througout the 29 // test. 30 const char kProtectedManifest[] = "http://www.protected.com/cache.manifest"; 31 const char kNormalManifest[] = "http://www.normal.com/cache.manifest"; 32 const char kSessionOnlyManifest[] = "http://www.sessiononly.com/cache.manifest"; 33 34 class MockURLRequestContextGetter : public net::URLRequestContextGetter { 35 public: 36 MockURLRequestContextGetter( 37 net::URLRequestContext* context, 38 base::MessageLoopProxy* message_loop_proxy) 39 : context_(context), message_loop_proxy_(message_loop_proxy) { 40 } 41 42 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { 43 return context_; 44 } 45 46 virtual scoped_refptr<base::SingleThreadTaskRunner> 47 GetNetworkTaskRunner() const OVERRIDE { 48 return message_loop_proxy_; 49 } 50 51 protected: 52 virtual ~MockURLRequestContextGetter() {} 53 54 private: 55 net::URLRequestContext* context_; 56 scoped_refptr<base::SingleThreadTaskRunner> message_loop_proxy_; 57 }; 58 59 } // namespace 60 61 class ChromeAppCacheServiceTest : public testing::Test { 62 public: 63 ChromeAppCacheServiceTest() 64 : kProtectedManifestURL(kProtectedManifest), 65 kNormalManifestURL(kNormalManifest), 66 kSessionOnlyManifestURL(kSessionOnlyManifest), 67 file_thread_(BrowserThread::FILE, &message_loop_), 68 file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING, 69 &message_loop_), 70 cache_thread_(BrowserThread::CACHE, &message_loop_), 71 io_thread_(BrowserThread::IO, &message_loop_) {} 72 73 protected: 74 scoped_refptr<ChromeAppCacheService> CreateAppCacheServiceImpl( 75 const base::FilePath& appcache_path, 76 bool init_storage); 77 void InsertDataIntoAppCache(ChromeAppCacheService* appcache_service); 78 79 base::MessageLoopForIO message_loop_; 80 base::ScopedTempDir temp_dir_; 81 const GURL kProtectedManifestURL; 82 const GURL kNormalManifestURL; 83 const GURL kSessionOnlyManifestURL; 84 85 private: 86 BrowserThreadImpl file_thread_; 87 BrowserThreadImpl file_user_blocking_thread_; 88 BrowserThreadImpl cache_thread_; 89 BrowserThreadImpl io_thread_; 90 TestBrowserContext browser_context_; 91 }; 92 93 scoped_refptr<ChromeAppCacheService> 94 ChromeAppCacheServiceTest::CreateAppCacheServiceImpl( 95 const base::FilePath& appcache_path, 96 bool init_storage) { 97 scoped_refptr<ChromeAppCacheService> appcache_service = 98 new ChromeAppCacheService(NULL); 99 scoped_refptr<MockSpecialStoragePolicy> mock_policy = 100 new MockSpecialStoragePolicy; 101 mock_policy->AddProtected(kProtectedManifestURL.GetOrigin()); 102 mock_policy->AddSessionOnly(kSessionOnlyManifestURL.GetOrigin()); 103 scoped_refptr<MockURLRequestContextGetter> mock_request_context_getter = 104 new MockURLRequestContextGetter( 105 browser_context_.GetResourceContext()->GetRequestContext(), 106 message_loop_.message_loop_proxy().get()); 107 BrowserThread::PostTask( 108 BrowserThread::IO, 109 FROM_HERE, 110 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, 111 appcache_service.get(), 112 appcache_path, 113 browser_context_.GetResourceContext(), 114 mock_request_context_getter, 115 mock_policy)); 116 // Steps needed to initialize the storage of AppCache data. 117 message_loop_.RunUntilIdle(); 118 if (init_storage) { 119 appcache::AppCacheStorageImpl* storage = 120 static_cast<appcache::AppCacheStorageImpl*>( 121 appcache_service->storage()); 122 storage->database_->db_connection(); 123 storage->disk_cache(); 124 message_loop_.RunUntilIdle(); 125 } 126 return appcache_service; 127 } 128 129 void ChromeAppCacheServiceTest::InsertDataIntoAppCache( 130 ChromeAppCacheService* appcache_service) { 131 AppCacheTestHelper appcache_helper; 132 appcache_helper.AddGroupAndCache(appcache_service, kNormalManifestURL); 133 appcache_helper.AddGroupAndCache(appcache_service, kProtectedManifestURL); 134 appcache_helper.AddGroupAndCache(appcache_service, kSessionOnlyManifestURL); 135 136 // Verify that adding the data succeeded 137 std::set<GURL> origins; 138 appcache_helper.GetOriginsWithCaches(appcache_service, &origins); 139 ASSERT_EQ(3UL, origins.size()); 140 ASSERT_TRUE(origins.find(kProtectedManifestURL.GetOrigin()) != origins.end()); 141 ASSERT_TRUE(origins.find(kNormalManifestURL.GetOrigin()) != origins.end()); 142 ASSERT_TRUE(origins.find(kSessionOnlyManifestURL.GetOrigin()) != 143 origins.end()); 144 } 145 146 TEST_F(ChromeAppCacheServiceTest, KeepOnDestruction) { 147 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 148 base::FilePath appcache_path = 149 temp_dir_.path().Append(kTestingAppCacheDirname); 150 151 // Create a ChromeAppCacheService and insert data into it 152 scoped_refptr<ChromeAppCacheService> appcache_service = 153 CreateAppCacheServiceImpl(appcache_path, true); 154 ASSERT_TRUE(base::PathExists(appcache_path)); 155 ASSERT_TRUE(base::PathExists(appcache_path.AppendASCII("Index"))); 156 InsertDataIntoAppCache(appcache_service.get()); 157 158 // Test: delete the ChromeAppCacheService 159 appcache_service = NULL; 160 message_loop_.RunUntilIdle(); 161 162 // Recreate the appcache (for reading the data back) 163 appcache_service = CreateAppCacheServiceImpl(appcache_path, false); 164 165 // The directory is still there 166 ASSERT_TRUE(base::PathExists(appcache_path)); 167 168 // The appcache data is also there, except the session-only origin. 169 AppCacheTestHelper appcache_helper; 170 std::set<GURL> origins; 171 appcache_helper.GetOriginsWithCaches(appcache_service.get(), &origins); 172 EXPECT_EQ(2UL, origins.size()); 173 EXPECT_TRUE(origins.find(kProtectedManifestURL.GetOrigin()) != origins.end()); 174 EXPECT_TRUE(origins.find(kNormalManifestURL.GetOrigin()) != origins.end()); 175 EXPECT_TRUE(origins.find(kSessionOnlyManifestURL.GetOrigin()) == 176 origins.end()); 177 178 // Delete and let cleanup tasks run prior to returning. 179 appcache_service = NULL; 180 message_loop_.RunUntilIdle(); 181 } 182 183 TEST_F(ChromeAppCacheServiceTest, SaveSessionState) { 184 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 185 base::FilePath appcache_path = 186 temp_dir_.path().Append(kTestingAppCacheDirname); 187 188 // Create a ChromeAppCacheService and insert data into it 189 scoped_refptr<ChromeAppCacheService> appcache_service = 190 CreateAppCacheServiceImpl(appcache_path, true); 191 ASSERT_TRUE(base::PathExists(appcache_path)); 192 ASSERT_TRUE(base::PathExists(appcache_path.AppendASCII("Index"))); 193 InsertDataIntoAppCache(appcache_service.get()); 194 195 // Save session state. This should bypass the destruction-time deletion. 196 appcache_service->set_force_keep_session_state(); 197 198 // Test: delete the ChromeAppCacheService 199 appcache_service = NULL; 200 message_loop_.RunUntilIdle(); 201 202 // Recreate the appcache (for reading the data back) 203 appcache_service = CreateAppCacheServiceImpl(appcache_path, false); 204 205 // The directory is still there 206 ASSERT_TRUE(base::PathExists(appcache_path)); 207 208 // No appcache data was deleted. 209 AppCacheTestHelper appcache_helper; 210 std::set<GURL> origins; 211 appcache_helper.GetOriginsWithCaches(appcache_service.get(), &origins); 212 EXPECT_EQ(3UL, origins.size()); 213 EXPECT_TRUE(origins.find(kProtectedManifestURL.GetOrigin()) != origins.end()); 214 EXPECT_TRUE(origins.find(kNormalManifestURL.GetOrigin()) != origins.end()); 215 EXPECT_TRUE(origins.find(kSessionOnlyManifestURL.GetOrigin()) != 216 origins.end()); 217 218 // Delete and let cleanup tasks run prior to returning. 219 appcache_service = NULL; 220 message_loop_.RunUntilIdle(); 221 } 222 223 } // namespace content 224