| OLD | NEW |
| (Empty) | |
| 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 <stddef.h> |
| 6 #include <stdint.h> |
| 7 |
| 8 #include <algorithm> |
| 9 #include <set> |
| 10 #include <string> |
| 11 #include <vector> |
| 12 |
| 13 #include "base/bind.h" |
| 14 #include "base/macros.h" |
| 15 #include "base/strings/stringprintf.h" |
| 16 #include "build/build_config.h" |
| 17 #include "chrome/browser/password_manager/password_store_factory.h" |
| 18 #include "chrome/browser/profiles/profile_manager.h" |
| 19 #include "chrome/browser/profiles/profile_statistics.h" |
| 20 #include "chrome/browser/profiles/profile_statistics_aggregator.h" |
| 21 #include "chrome/browser/profiles/profile_statistics_constants.h" |
| 22 #include "chrome/browser/profiles/profile_statistics_types.h" |
| 23 #include "chrome/browser/ui/browser.h" |
| 24 #include "chrome/test/base/in_process_browser_test.h" |
| 25 #include "components/password_manager/core/browser/password_manager_test_utils.h
" |
| 26 #include "components/password_manager/core/browser/test_password_store.h" |
| 27 #include "content/public/test/test_utils.h" |
| 28 |
| 29 namespace { |
| 30 |
| 31 const std::set<std::string> stats_categories { |
| 32 profiles::kProfileStatisticsBrowsingHistory, |
| 33 profiles::kProfileStatisticsPasswords, |
| 34 profiles::kProfileStatisticsBookmarks, |
| 35 profiles::kProfileStatisticsSettings}; |
| 36 |
| 37 const size_t num_of_stats_categories = stats_categories.size(); |
| 38 |
| 39 bool IsProfileCategoryStatEqual(const profiles::ProfileCategoryStat& a, |
| 40 const profiles::ProfileCategoryStat& b) { |
| 41 return a.category == b.category && a.count == b.count && |
| 42 a.success == b.success; |
| 43 } |
| 44 |
| 45 std::string ProfileCategoryStatToString( |
| 46 const profiles::ProfileCategoryStat& a) { |
| 47 return base::StringPrintf("category = %s, count = %d, success = %s", |
| 48 a.category.c_str(), a.count, a.success ? "true" : "false"); |
| 49 } |
| 50 |
| 51 ::testing::AssertionResult AssertionProfileCategoryStatEqual( |
| 52 const char* actual_expression, |
| 53 const char* expected_expression, |
| 54 const profiles::ProfileCategoryStat& actual_value, |
| 55 const profiles::ProfileCategoryStat& expected_value) { |
| 56 if (IsProfileCategoryStatEqual(actual_value, expected_value)) { |
| 57 return ::testing::AssertionSuccess(); |
| 58 } else { |
| 59 return ::testing::AssertionFailure() |
| 60 << "Value of: " << actual_expression |
| 61 << "\n Actual: " << ProfileCategoryStatToString(actual_value) |
| 62 << "\nExpected: " << expected_expression |
| 63 << "\nWhich is: " << ProfileCategoryStatToString(expected_value); |
| 64 } |
| 65 } |
| 66 |
| 67 ::testing::AssertionResult AssertionProfileCategoryStatsEqual( |
| 68 const char* actual_expression, |
| 69 const char* expected_expression, |
| 70 const profiles::ProfileCategoryStats& actual_value, |
| 71 const profiles::ProfileCategoryStats& expected_value) { |
| 72 size_t actual_count = actual_value.size(); |
| 73 size_t expected_count = expected_value.size(); |
| 74 std::vector<bool> actual_unused(actual_count, true); |
| 75 std::vector<bool> expected_unused(expected_count, true); |
| 76 |
| 77 bool match_failed = actual_count != expected_count; |
| 78 for (size_t actual_pos = 0; actual_pos < actual_count; actual_pos++) { |
| 79 for (size_t expected_pos = 0; expected_pos < expected_count; |
| 80 expected_pos++) { |
| 81 if (expected_unused[expected_pos] && |
| 82 IsProfileCategoryStatEqual(actual_value[actual_pos], |
| 83 expected_value[expected_pos])) { |
| 84 actual_unused[actual_pos] = false; |
| 85 expected_unused[expected_pos] = false; |
| 86 break; |
| 87 } |
| 88 } |
| 89 |
| 90 if (actual_unused[actual_pos]) |
| 91 match_failed = true; |
| 92 } |
| 93 |
| 94 if (!match_failed) { |
| 95 return ::testing::AssertionSuccess(); |
| 96 } else { |
| 97 ::testing::AssertionResult result = testing::AssertionFailure(); |
| 98 result << "ProfileCategoryStats are not equal."; |
| 99 |
| 100 result << "\n Actual: " << actual_expression; |
| 101 bool actual_printed = false; |
| 102 for (size_t i = 0; i < actual_count; i++) { |
| 103 if (actual_unused[i]) { |
| 104 result << "\n" |
| 105 << (actual_printed ? " " : "Unmatched rows: ") |
| 106 << ProfileCategoryStatToString(actual_value[i]); |
| 107 actual_printed = true; |
| 108 } |
| 109 } |
| 110 if (!actual_printed) |
| 111 result << "(no unmatched rows found in actual value)"; |
| 112 |
| 113 |
| 114 result << "\nExpected: " << expected_expression; |
| 115 bool expected_printed = false; |
| 116 for (size_t i = 0; i < expected_count; i++) { |
| 117 if (expected_unused[i]) { |
| 118 result << "\n" |
| 119 << (expected_printed ? " " : "Unmatched rows: ") |
| 120 << ProfileCategoryStatToString(expected_value[i]); |
| 121 expected_printed = true; |
| 122 } |
| 123 } |
| 124 if (!expected_printed) |
| 125 result << "(no unmatched rows found in expected value)"; |
| 126 |
| 127 return result; |
| 128 } |
| 129 } |
| 130 |
| 131 class ProfileStatisticsAggregatorState { |
| 132 public: |
| 133 explicit ProfileStatisticsAggregatorState(base::RunLoop* run_loop) |
| 134 : run_loop_(run_loop) {} |
| 135 |
| 136 ProfileStatisticsAggregatorState(base::RunLoop* run_loop, |
| 137 size_t required_stat_count) |
| 138 : run_loop_(run_loop), |
| 139 required_stat_count_( |
| 140 std::min(num_of_stats_categories, required_stat_count)) {} |
| 141 |
| 142 void callback(profiles::ProfileCategoryStats stats_return) { |
| 143 size_t newCount = stats_return.size(); |
| 144 // If newCount is 1, then a new GatherStatistics task has started. Discard |
| 145 // the old statistics by setting oldCount to 0 in this case. |
| 146 size_t oldCount = newCount == 1 ? 0 : stats_.size(); |
| 147 |
| 148 EXPECT_LT(oldCount, newCount); |
| 149 if (oldCount < newCount) { |
| 150 for (size_t i = 0; i < oldCount; i++) { |
| 151 // Exisiting statistics must be the same. |
| 152 EXPECT_PRED_FORMAT2(AssertionProfileCategoryStatEqual, |
| 153 stats_[i], stats_return[i]); |
| 154 // The new statistic categories must be different. |
| 155 for (size_t j = oldCount; j < newCount; j++) |
| 156 EXPECT_NE(stats_[i].category, stats_return[j].category); |
| 157 } |
| 158 |
| 159 for (size_t j = oldCount; j < newCount; j++) { |
| 160 EXPECT_EQ(1u, stats_categories.count(stats_return[j].category)); |
| 161 // Count the number of statistics failures (incrementally). |
| 162 if (!stats_return[j].success) |
| 163 num_of_fails_++; |
| 164 } |
| 165 } |
| 166 stats_ = stats_return; |
| 167 |
| 168 EXPECT_GE(num_of_stats_categories, newCount); |
| 169 if (required_stat_count_ <= newCount) |
| 170 run_loop_->Quit(); |
| 171 } |
| 172 |
| 173 profiles::ProfileCategoryStats GetStats() const { return stats_; } |
| 174 int GetNumOfFails() const { return num_of_fails_; } |
| 175 void SetRunLoopAndRequiredStatCount(base::RunLoop* run_loop, |
| 176 size_t required_stat_count) { |
| 177 run_loop_ = run_loop; |
| 178 required_stat_count_ = std::min(num_of_stats_categories, |
| 179 required_stat_count); |
| 180 } |
| 181 |
| 182 private: |
| 183 profiles::ProfileCategoryStats stats_; |
| 184 int num_of_fails_ = 0; |
| 185 base::RunLoop* run_loop_; |
| 186 size_t required_stat_count_ = num_of_stats_categories; |
| 187 }; |
| 188 |
| 189 void WaitMilliseconds(int time_in_milliseconds) { |
| 190 base::RunLoop run_loop; |
| 191 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 192 FROM_HERE, run_loop.QuitClosure(), |
| 193 base::TimeDelta::FromMilliseconds(time_in_milliseconds)); |
| 194 run_loop.Run(); |
| 195 } |
| 196 |
| 197 } // namespace |
| 198 |
| 199 class ProfileStatisticsBrowserTest : public InProcessBrowserTest { |
| 200 public: |
| 201 void SetUpOnMainThread() override { |
| 202 // Use TestPasswordStore to remove a possible race. Normally the |
| 203 // PasswordStore does its database manipulation on the DB thread, which |
| 204 // creates a possible race during navigation. Specifically the |
| 205 // PasswordManager will ignore any forms in a page if the load from the |
| 206 // PasswordStore has not completed. |
| 207 PasswordStoreFactory::GetInstance()->SetTestingFactory( |
| 208 browser()->profile(), |
| 209 password_manager::BuildPasswordStore< |
| 210 content::BrowserContext, password_manager::TestPasswordStore>); |
| 211 } |
| 212 }; |
| 213 |
| 214 using ProfileStatisticsBrowserDeathTest = ProfileStatisticsBrowserTest; |
| 215 |
| 216 IN_PROC_BROWSER_TEST_F(ProfileStatisticsBrowserTest, GatherStatistics) { |
| 217 Profile* profile = ProfileManager::GetActiveUserProfile(); |
| 218 ASSERT_TRUE(profile); |
| 219 |
| 220 base::RunLoop run_loop; |
| 221 ProfileStatisticsAggregatorState state(&run_loop); |
| 222 EXPECT_EQ(false, ProfileStatistics::HasAggregator(profile)); |
| 223 ProfileStatistics::GatherProfileStatistics( |
| 224 profile, |
| 225 base::Bind(&ProfileStatisticsAggregatorState::callback, |
| 226 base::Unretained(&state))); |
| 227 EXPECT_EQ(true, ProfileStatistics::HasAggregator(profile)); |
| 228 EXPECT_EQ(1u, ProfileStatistics::GetAggregator(profile)->GetCallbackCount()); |
| 229 run_loop.Run(); |
| 230 |
| 231 EXPECT_EQ(0, state.GetNumOfFails()); |
| 232 |
| 233 profiles::ProfileCategoryStats stats = state.GetStats(); |
| 234 for (const auto& stat : stats) { |
| 235 if (stat.category != profiles::kProfileStatisticsSettings) |
| 236 EXPECT_EQ(0, stat.count); |
| 237 } |
| 238 |
| 239 EXPECT_PRED_FORMAT2(AssertionProfileCategoryStatsEqual, stats, |
| 240 ProfileStatistics::GetProfileStatisticsFromCache(profile->GetPath())); |
| 241 } |
| 242 |
| 243 IN_PROC_BROWSER_TEST_F(ProfileStatisticsBrowserTest, |
| 244 GatherStatisticsTwoCallbacks) { |
| 245 Profile* profile = ProfileManager::GetActiveUserProfile(); |
| 246 ASSERT_TRUE(profile); |
| 247 |
| 248 base::RunLoop run_loop1a; |
| 249 base::RunLoop run_loop1b; |
| 250 base::RunLoop run_loop2; |
| 251 ProfileStatisticsAggregatorState state1(&run_loop1a, 1u); |
| 252 ProfileStatisticsAggregatorState state2(&run_loop2); |
| 253 |
| 254 EXPECT_EQ(false, ProfileStatistics::HasAggregator(profile)); |
| 255 ProfileStatistics::GatherProfileStatistics( |
| 256 profile, |
| 257 base::Bind(&ProfileStatisticsAggregatorState::callback, |
| 258 base::Unretained(&state1))); |
| 259 EXPECT_EQ(true, ProfileStatistics::HasAggregator(profile)); |
| 260 EXPECT_EQ(1u, ProfileStatistics::GetAggregator(profile)->GetCallbackCount()); |
| 261 run_loop1a.Run(); |
| 262 |
| 263 state1.SetRunLoopAndRequiredStatCount(&run_loop1b, SIZE_MAX); |
| 264 |
| 265 ProfileStatistics::GatherProfileStatistics( |
| 266 profile, |
| 267 base::Bind(&ProfileStatisticsAggregatorState::callback, |
| 268 base::Unretained(&state2))); |
| 269 EXPECT_EQ(true, ProfileStatistics::HasAggregator(profile)); |
| 270 EXPECT_EQ(2u, ProfileStatistics::GetAggregator(profile)->GetCallbackCount()); |
| 271 run_loop1b.Run(); |
| 272 run_loop2.Run(); |
| 273 |
| 274 EXPECT_EQ(0, state1.GetNumOfFails()); |
| 275 |
| 276 EXPECT_PRED_FORMAT2(AssertionProfileCategoryStatsEqual, |
| 277 state1.GetStats(), state2.GetStats()); |
| 278 } |
| 279 |
| 280 IN_PROC_BROWSER_TEST_F(ProfileStatisticsBrowserTest, CloseBrowser) { |
| 281 Profile* profile = ProfileManager::GetActiveUserProfile(); |
| 282 ASSERT_TRUE(profile); |
| 283 |
| 284 EXPECT_EQ(false, ProfileStatistics::HasAggregator(profile)); |
| 285 CloseBrowserSynchronously(browser()); |
| 286 EXPECT_EQ(true, ProfileStatistics::HasAggregator(profile)); |
| 287 EXPECT_EQ(0u, ProfileStatistics::GetAggregator(profile)->GetCallbackCount()); |
| 288 } |
| OLD | NEW |