1 // Copyright 2013 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/files/scoped_temp_dir.h" 7 #include "base/memory/scoped_ptr.h" 8 #include "base/test/sequenced_worker_pool_owner.h" 9 #include "content/browser/media/webrtc_identity_store.h" 10 #include "content/public/test/test_browser_thread_bundle.h" 11 #include "content/public/test/test_utils.h" 12 #include "net/base/net_errors.h" 13 #include "sql/connection.h" 14 #include "sql/test/test_helpers.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "url/gurl.h" 17 18 namespace content { 19 20 static const char* kFakeOrigin = "http://foo.com"; 21 static const char* kFakeIdentityName1 = "name1"; 22 static const char* kFakeIdentityName2 = "name2"; 23 static const char* kFakeCommonName1 = "cname1"; 24 static const char* kFakeCommonName2 = "cname2"; 25 26 static void OnRequestCompleted(bool* completed, 27 std::string* out_cert, 28 std::string* out_key, 29 int error, 30 const std::string& certificate, 31 const std::string& private_key) { 32 ASSERT_EQ(net::OK, error); 33 ASSERT_NE("", certificate); 34 ASSERT_NE("", private_key); 35 *completed = true; 36 *out_cert = certificate; 37 *out_key = private_key; 38 } 39 40 class WebRTCIdentityStoreTest : public testing::Test { 41 public: 42 WebRTCIdentityStoreTest() 43 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP | 44 TestBrowserThreadBundle::REAL_DB_THREAD), 45 pool_owner_( 46 new base::SequencedWorkerPoolOwner(3, "WebRTCIdentityStoreTest")), 47 webrtc_identity_store_( 48 new WebRTCIdentityStore(base::FilePath(), NULL)) { 49 webrtc_identity_store_->SetTaskRunnerForTesting(pool_owner_->pool()); 50 } 51 52 virtual ~WebRTCIdentityStoreTest() { 53 pool_owner_->pool()->Shutdown(); 54 } 55 56 void SetValidityPeriod(base::TimeDelta validity_period) { 57 webrtc_identity_store_->SetValidityPeriodForTesting(validity_period); 58 } 59 60 void RunUntilIdle() { 61 RunAllPendingInMessageLoop(BrowserThread::DB); 62 RunAllPendingInMessageLoop(BrowserThread::IO); 63 pool_owner_->pool()->FlushForTesting(); 64 base::RunLoop().RunUntilIdle(); 65 } 66 67 base::Closure RequestIdentityAndRunUtilIdle(const std::string& origin, 68 const std::string& identity_name, 69 const std::string& common_name, 70 bool* completed, 71 std::string* certificate, 72 std::string* private_key) { 73 base::Closure cancel_callback = webrtc_identity_store_->RequestIdentity( 74 GURL(origin), 75 identity_name, 76 common_name, 77 base::Bind(&OnRequestCompleted, completed, certificate, private_key)); 78 EXPECT_FALSE(cancel_callback.is_null()); 79 RunUntilIdle(); 80 return cancel_callback; 81 } 82 83 void Restart(const base::FilePath& path) { 84 webrtc_identity_store_ = new WebRTCIdentityStore(path, NULL); 85 webrtc_identity_store_->SetTaskRunnerForTesting(pool_owner_->pool()); 86 } 87 88 protected: 89 TestBrowserThreadBundle browser_thread_bundle_; 90 scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_; 91 scoped_refptr<WebRTCIdentityStore> webrtc_identity_store_; 92 }; 93 94 TEST_F(WebRTCIdentityStoreTest, RequestIdentity) { 95 bool completed = false; 96 std::string dummy; 97 base::Closure cancel_callback = 98 RequestIdentityAndRunUtilIdle(kFakeOrigin, 99 kFakeIdentityName1, 100 kFakeCommonName1, 101 &completed, 102 &dummy, 103 &dummy); 104 EXPECT_TRUE(completed); 105 } 106 107 TEST_F(WebRTCIdentityStoreTest, CancelRequest) { 108 bool completed = false; 109 std::string dummy; 110 base::Closure cancel_callback = webrtc_identity_store_->RequestIdentity( 111 GURL(kFakeOrigin), 112 kFakeIdentityName1, 113 kFakeCommonName1, 114 base::Bind(&OnRequestCompleted, &completed, &dummy, &dummy)); 115 ASSERT_FALSE(cancel_callback.is_null()); 116 cancel_callback.Run(); 117 118 RunUntilIdle(); 119 EXPECT_FALSE(completed); 120 } 121 122 TEST_F(WebRTCIdentityStoreTest, ConcurrentUniqueRequests) { 123 bool completed_1 = false; 124 bool completed_2 = false; 125 std::string dummy; 126 base::Closure cancel_callback_1 = webrtc_identity_store_->RequestIdentity( 127 GURL(kFakeOrigin), 128 kFakeIdentityName1, 129 kFakeCommonName1, 130 base::Bind(&OnRequestCompleted, &completed_1, &dummy, &dummy)); 131 ASSERT_FALSE(cancel_callback_1.is_null()); 132 133 base::Closure cancel_callback_2 = webrtc_identity_store_->RequestIdentity( 134 GURL(kFakeOrigin), 135 kFakeIdentityName2, 136 kFakeCommonName1, 137 base::Bind(&OnRequestCompleted, &completed_2, &dummy, &dummy)); 138 ASSERT_FALSE(cancel_callback_2.is_null()); 139 140 RunUntilIdle(); 141 EXPECT_TRUE(completed_1); 142 EXPECT_TRUE(completed_2); 143 } 144 145 TEST_F(WebRTCIdentityStoreTest, DifferentCommonNameReturnNewIdentity) { 146 bool completed_1 = false; 147 bool completed_2 = false; 148 std::string cert_1, cert_2, key_1, key_2; 149 150 base::Closure cancel_callback_1 = 151 RequestIdentityAndRunUtilIdle(kFakeOrigin, 152 kFakeIdentityName1, 153 kFakeCommonName1, 154 &completed_1, 155 &cert_1, 156 &key_1); 157 158 base::Closure cancel_callback_2 = 159 RequestIdentityAndRunUtilIdle(kFakeOrigin, 160 kFakeIdentityName1, 161 kFakeCommonName2, 162 &completed_2, 163 &cert_2, 164 &key_2); 165 166 EXPECT_TRUE(completed_1); 167 EXPECT_TRUE(completed_2); 168 EXPECT_NE(cert_1, cert_2); 169 EXPECT_NE(key_1, key_2); 170 } 171 172 TEST_F(WebRTCIdentityStoreTest, SerialIdenticalRequests) { 173 bool completed_1 = false; 174 bool completed_2 = false; 175 std::string cert_1, cert_2, key_1, key_2; 176 177 base::Closure cancel_callback_1 = 178 RequestIdentityAndRunUtilIdle(kFakeOrigin, 179 kFakeIdentityName1, 180 kFakeCommonName1, 181 &completed_1, 182 &cert_1, 183 &key_1); 184 185 base::Closure cancel_callback_2 = 186 RequestIdentityAndRunUtilIdle(kFakeOrigin, 187 kFakeIdentityName1, 188 kFakeCommonName1, 189 &completed_2, 190 &cert_2, 191 &key_2); 192 193 EXPECT_TRUE(completed_1); 194 EXPECT_TRUE(completed_2); 195 EXPECT_EQ(cert_1, cert_2); 196 EXPECT_EQ(key_1, key_2); 197 } 198 199 TEST_F(WebRTCIdentityStoreTest, ConcurrentIdenticalRequestsJoined) { 200 bool completed_1 = false; 201 bool completed_2 = false; 202 std::string cert_1, cert_2, key_1, key_2; 203 204 base::Closure cancel_callback_1 = webrtc_identity_store_->RequestIdentity( 205 GURL(kFakeOrigin), 206 kFakeIdentityName1, 207 kFakeCommonName1, 208 base::Bind(&OnRequestCompleted, &completed_1, &cert_1, &key_1)); 209 ASSERT_FALSE(cancel_callback_1.is_null()); 210 211 base::Closure cancel_callback_2 = webrtc_identity_store_->RequestIdentity( 212 GURL(kFakeOrigin), 213 kFakeIdentityName1, 214 kFakeCommonName1, 215 base::Bind(&OnRequestCompleted, &completed_2, &cert_2, &key_2)); 216 ASSERT_FALSE(cancel_callback_2.is_null()); 217 218 RunUntilIdle(); 219 EXPECT_TRUE(completed_1); 220 EXPECT_TRUE(completed_2); 221 EXPECT_EQ(cert_1, cert_2); 222 EXPECT_EQ(key_1, key_2); 223 } 224 225 TEST_F(WebRTCIdentityStoreTest, CancelOneOfIdenticalRequests) { 226 bool completed_1 = false; 227 bool completed_2 = false; 228 std::string cert_1, cert_2, key_1, key_2; 229 230 base::Closure cancel_callback_1 = webrtc_identity_store_->RequestIdentity( 231 GURL(kFakeOrigin), 232 kFakeIdentityName1, 233 kFakeCommonName1, 234 base::Bind(&OnRequestCompleted, &completed_1, &cert_1, &key_1)); 235 ASSERT_FALSE(cancel_callback_1.is_null()); 236 237 base::Closure cancel_callback_2 = webrtc_identity_store_->RequestIdentity( 238 GURL(kFakeOrigin), 239 kFakeIdentityName1, 240 kFakeCommonName1, 241 base::Bind(&OnRequestCompleted, &completed_2, &cert_2, &key_2)); 242 ASSERT_FALSE(cancel_callback_2.is_null()); 243 244 cancel_callback_1.Run(); 245 246 RunUntilIdle(); 247 EXPECT_FALSE(completed_1); 248 EXPECT_TRUE(completed_2); 249 } 250 251 TEST_F(WebRTCIdentityStoreTest, DeleteDataAndGenerateNewIdentity) { 252 bool completed_1 = false; 253 bool completed_2 = false; 254 std::string cert_1, cert_2, key_1, key_2; 255 256 // Generate the first identity. 257 base::Closure cancel_callback_1 = 258 RequestIdentityAndRunUtilIdle(kFakeOrigin, 259 kFakeIdentityName1, 260 kFakeCommonName1, 261 &completed_1, 262 &cert_1, 263 &key_1); 264 265 // Clear the data and the second request should return a new identity. 266 webrtc_identity_store_->DeleteBetween( 267 base::Time(), base::Time::Now(), base::Bind(&base::DoNothing)); 268 RunUntilIdle(); 269 270 base::Closure cancel_callback_2 = 271 RequestIdentityAndRunUtilIdle(kFakeOrigin, 272 kFakeIdentityName1, 273 kFakeCommonName1, 274 &completed_2, 275 &cert_2, 276 &key_2); 277 278 EXPECT_TRUE(completed_1); 279 EXPECT_TRUE(completed_2); 280 EXPECT_NE(cert_1, cert_2); 281 EXPECT_NE(key_1, key_2); 282 } 283 284 TEST_F(WebRTCIdentityStoreTest, ExpiredIdentityDeleted) { 285 // The identities will expire immediately after creation. 286 SetValidityPeriod(base::TimeDelta::FromMilliseconds(0)); 287 288 bool completed_1 = false; 289 bool completed_2 = false; 290 std::string cert_1, cert_2, key_1, key_2; 291 292 base::Closure cancel_callback_1 = 293 RequestIdentityAndRunUtilIdle(kFakeOrigin, 294 kFakeIdentityName1, 295 kFakeCommonName1, 296 &completed_1, 297 &cert_1, 298 &key_1); 299 EXPECT_TRUE(completed_1); 300 301 // Check that the old identity is not returned. 302 base::Closure cancel_callback_2 = 303 RequestIdentityAndRunUtilIdle(kFakeOrigin, 304 kFakeIdentityName1, 305 kFakeCommonName1, 306 &completed_2, 307 &cert_2, 308 &key_2); 309 EXPECT_TRUE(completed_2); 310 EXPECT_NE(cert_1, cert_2); 311 EXPECT_NE(key_1, key_2); 312 } 313 314 TEST_F(WebRTCIdentityStoreTest, IdentityPersistentAcrossRestart) { 315 base::ScopedTempDir temp_dir; 316 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 317 Restart(temp_dir.path()); 318 319 bool completed_1 = false; 320 bool completed_2 = false; 321 std::string cert_1, cert_2, key_1, key_2; 322 323 // Creates an identity. 324 base::Closure cancel_callback_1 = 325 RequestIdentityAndRunUtilIdle(kFakeOrigin, 326 kFakeIdentityName1, 327 kFakeCommonName1, 328 &completed_1, 329 &cert_1, 330 &key_1); 331 EXPECT_TRUE(completed_1); 332 333 Restart(temp_dir.path()); 334 335 // Check that the same identity is returned after the restart. 336 base::Closure cancel_callback_2 = 337 RequestIdentityAndRunUtilIdle(kFakeOrigin, 338 kFakeIdentityName1, 339 kFakeCommonName1, 340 &completed_2, 341 &cert_2, 342 &key_2); 343 EXPECT_TRUE(completed_2); 344 EXPECT_EQ(cert_1, cert_2); 345 EXPECT_EQ(key_1, key_2); 346 } 347 348 TEST_F(WebRTCIdentityStoreTest, HandleDBErrors) { 349 base::ScopedTempDir temp_dir; 350 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 351 Restart(temp_dir.path()); 352 353 bool completed_1 = false; 354 std::string cert_1, key_1; 355 356 // Creates an identity. 357 RequestIdentityAndRunUtilIdle(kFakeOrigin, 358 kFakeIdentityName1, 359 kFakeCommonName1, 360 &completed_1, 361 &cert_1, 362 &key_1); 363 364 // Make the table corrupted. 365 base::FilePath db_path = 366 temp_dir.path().Append(FILE_PATH_LITERAL("WebRTCIdentityStore")); 367 EXPECT_TRUE(sql::test::CorruptSizeInHeader(db_path)); 368 369 // Reset to commit the DB changes, which should fail and not crash. 370 webrtc_identity_store_ = NULL; 371 RunUntilIdle(); 372 373 // Verifies the corrupted table was razed. 374 scoped_ptr<sql::Connection> db(new sql::Connection()); 375 EXPECT_TRUE(db->Open(db_path)); 376 EXPECT_EQ(0U, sql::test::CountSQLTables(db.get())); 377 } 378 379 } // namespace content 380