1// Copyright 2014 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/file_util.h" 7#include "base/files/scoped_temp_dir.h" 8#include "base/memory/ref_counted.h" 9#include "base/memory/scoped_vector.h" 10#include "base/message_loop/message_loop.h" 11#include "base/run_loop.h" 12#include "base/stl_util.h" 13#include "base/thread_task_runner_handle.h" 14#include "base/time/time.h" 15#include "chrome/browser/net/quota_policy_channel_id_store.h" 16#include "content/public/test/mock_special_storage_policy.h" 17#include "content/public/test/test_browser_thread_bundle.h" 18#include "net/base/test_data_directory.h" 19#include "net/cookies/cookie_util.h" 20#include "net/ssl/ssl_client_cert_type.h" 21#include "net/test/cert_test_util.h" 22#include "sql/statement.h" 23#include "testing/gtest/include/gtest/gtest.h" 24 25const base::FilePath::CharType kTestChannelIDFilename[] = 26 FILE_PATH_LITERAL("ChannelID"); 27 28class QuotaPolicyChannelIDStoreTest : public testing::Test { 29 public: 30 void Load(ScopedVector<net::DefaultChannelIDStore::ChannelID>* channel_ids) { 31 base::RunLoop run_loop; 32 store_->Load(base::Bind(&QuotaPolicyChannelIDStoreTest::OnLoaded, 33 base::Unretained(this), 34 &run_loop)); 35 run_loop.Run(); 36 channel_ids->swap(channel_ids_); 37 channel_ids_.clear(); 38 } 39 40 void OnLoaded(base::RunLoop* run_loop, 41 scoped_ptr<ScopedVector<net::DefaultChannelIDStore::ChannelID> > 42 channel_ids) { 43 channel_ids_.swap(*channel_ids); 44 run_loop->Quit(); 45 } 46 47 protected: 48 static base::Time GetTestCertExpirationTime() { 49 // Cert expiration time from 'dumpasn1 unittest.originbound.der': 50 // GeneralizedTime 19/11/2111 02:23:45 GMT 51 // base::Time::FromUTCExploded can't generate values past 2038 on 32-bit 52 // linux, so we use the raw value here. 53 return base::Time::FromInternalValue(GG_INT64_C(16121816625000000)); 54 } 55 56 static base::Time GetTestCertCreationTime() { 57 // UTCTime 13/12/2011 02:23:45 GMT 58 base::Time::Exploded exploded_time; 59 exploded_time.year = 2011; 60 exploded_time.month = 12; 61 exploded_time.day_of_week = 0; // Unused. 62 exploded_time.day_of_month = 13; 63 exploded_time.hour = 2; 64 exploded_time.minute = 23; 65 exploded_time.second = 45; 66 exploded_time.millisecond = 0; 67 return base::Time::FromUTCExploded(exploded_time); 68 } 69 70 virtual void SetUp() { 71 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 72 store_ = new QuotaPolicyChannelIDStore( 73 temp_dir_.path().Append(kTestChannelIDFilename), 74 base::ThreadTaskRunnerHandle::Get(), 75 NULL); 76 ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids; 77 Load(&channel_ids); 78 ASSERT_EQ(0u, channel_ids.size()); 79 // Make sure the store gets written at least once. 80 store_->AddChannelID( 81 net::DefaultChannelIDStore::ChannelID("google.com", 82 base::Time::FromInternalValue(1), 83 base::Time::FromInternalValue(2), 84 "a", 85 "b")); 86 } 87 88 virtual void TearDown() { 89 store_ = NULL; 90 loop_.RunUntilIdle(); 91 } 92 93 base::ScopedTempDir temp_dir_; 94 scoped_refptr<QuotaPolicyChannelIDStore> store_; 95 ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids_; 96 base::MessageLoop loop_; 97}; 98 99// Test if data is stored as expected in the QuotaPolicy database. 100TEST_F(QuotaPolicyChannelIDStoreTest, TestPersistence) { 101 store_->AddChannelID( 102 net::DefaultChannelIDStore::ChannelID("foo.com", 103 base::Time::FromInternalValue(3), 104 base::Time::FromInternalValue(4), 105 "c", 106 "d")); 107 108 ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids; 109 // Replace the store effectively destroying the current one and forcing it 110 // to write its data to disk. Then we can see if after loading it again it 111 // is still there. 112 store_ = NULL; 113 // Make sure we wait until the destructor has run. 114 base::RunLoop().RunUntilIdle(); 115 store_ = new QuotaPolicyChannelIDStore( 116 temp_dir_.path().Append(kTestChannelIDFilename), 117 base::MessageLoopProxy::current(), 118 NULL); 119 120 // Reload and test for persistence 121 Load(&channel_ids); 122 ASSERT_EQ(2U, channel_ids.size()); 123 net::DefaultChannelIDStore::ChannelID* goog_channel_id; 124 net::DefaultChannelIDStore::ChannelID* foo_channel_id; 125 if (channel_ids[0]->server_identifier() == "google.com") { 126 goog_channel_id = channel_ids[0]; 127 foo_channel_id = channel_ids[1]; 128 } else { 129 goog_channel_id = channel_ids[1]; 130 foo_channel_id = channel_ids[0]; 131 } 132 ASSERT_EQ("google.com", goog_channel_id->server_identifier()); 133 ASSERT_STREQ("a", goog_channel_id->private_key().c_str()); 134 ASSERT_STREQ("b", goog_channel_id->cert().c_str()); 135 ASSERT_EQ(1, goog_channel_id->creation_time().ToInternalValue()); 136 ASSERT_EQ(2, goog_channel_id->expiration_time().ToInternalValue()); 137 ASSERT_EQ("foo.com", foo_channel_id->server_identifier()); 138 ASSERT_STREQ("c", foo_channel_id->private_key().c_str()); 139 ASSERT_STREQ("d", foo_channel_id->cert().c_str()); 140 ASSERT_EQ(3, foo_channel_id->creation_time().ToInternalValue()); 141 ASSERT_EQ(4, foo_channel_id->expiration_time().ToInternalValue()); 142 143 // Now delete the cert and check persistence again. 144 store_->DeleteChannelID(*channel_ids[0]); 145 store_->DeleteChannelID(*channel_ids[1]); 146 store_ = NULL; 147 // Make sure we wait until the destructor has run. 148 base::RunLoop().RunUntilIdle(); 149 channel_ids.clear(); 150 store_ = new QuotaPolicyChannelIDStore( 151 temp_dir_.path().Append(kTestChannelIDFilename), 152 base::MessageLoopProxy::current(), 153 NULL); 154 155 // Reload and check if the cert has been removed. 156 Load(&channel_ids); 157 ASSERT_EQ(0U, channel_ids.size()); 158} 159 160// Test if data is stored as expected in the QuotaPolicy database. 161TEST_F(QuotaPolicyChannelIDStoreTest, TestPolicy) { 162 store_->AddChannelID( 163 net::DefaultChannelIDStore::ChannelID("foo.com", 164 base::Time::FromInternalValue(3), 165 base::Time::FromInternalValue(4), 166 "c", 167 "d")); 168 169 ScopedVector<net::DefaultChannelIDStore::ChannelID> channel_ids; 170 // Replace the store effectively destroying the current one and forcing it 171 // to write its data to disk. Then we can see if after loading it again it 172 // is still there. 173 store_ = NULL; 174 // Make sure we wait until the destructor has run. 175 base::RunLoop().RunUntilIdle(); 176 // Specify storage policy that makes "foo.com" session only. 177 scoped_refptr<content::MockSpecialStoragePolicy> storage_policy = 178 new content::MockSpecialStoragePolicy(); 179 storage_policy->AddSessionOnly( 180 net::cookie_util::CookieOriginToURL("foo.com", true)); 181 // Reload store, it should still have both channel ids. 182 store_ = new QuotaPolicyChannelIDStore( 183 temp_dir_.path().Append(kTestChannelIDFilename), 184 base::MessageLoopProxy::current(), 185 storage_policy); 186 Load(&channel_ids); 187 ASSERT_EQ(2U, channel_ids.size()); 188 189 // Now close the store, and "foo.com" should be deleted according to policy. 190 store_ = NULL; 191 // Make sure we wait until the destructor has run. 192 base::RunLoop().RunUntilIdle(); 193 channel_ids.clear(); 194 store_ = new QuotaPolicyChannelIDStore( 195 temp_dir_.path().Append(kTestChannelIDFilename), 196 base::MessageLoopProxy::current(), 197 NULL); 198 199 // Reload and check that the "foo.com" cert has been removed. 200 Load(&channel_ids); 201 ASSERT_EQ(1U, channel_ids.size()); 202 ASSERT_EQ("google.com", channel_ids[0]->server_identifier()); 203} 204