Chromium Code Reviews| 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 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "base/strings/stringprintf.h" | |
| 10 #include "build/build_config.h" | |
| 11 #include "chrome/browser/password_manager/password_store_factory.h" | |
| 12 #include "chrome/browser/profiles/profile_manager.h" | |
| 13 #include "chrome/browser/profiles/profile_statistics.h" | |
| 14 #include "chrome/browser/ui/browser.h" | |
| 15 #include "chrome/test/base/in_process_browser_test.h" | |
| 16 #include "components/password_manager/core/browser/password_manager_test_utils.h " | |
| 17 #include "components/password_manager/core/browser/test_password_store.h" | |
| 18 #include "content/public/test/test_utils.h" | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 const std::set<std::string> stats_categories { | |
| 23 profiles::kProfileStatisticsBrowsingHistory, | |
| 24 profiles::kProfileStatisticsPasswords, | |
| 25 profiles::kProfileStatisticsBookmarks, | |
| 26 profiles::kProfileStatisticsSettings}; | |
| 27 | |
|
lwchkg
2016/01/13 17:21:55
Do you know why this empty row is marked as differ
Mike Lerman
2016/01/14 15:21:53
It's been added; it doesn't exist on the left (e.g
lwchkg
2016/01/16 18:07:50
Thanks. Didn't notice this one.
| |
| 28 const size_t num_of_stats_categories = stats_categories.size(); | |
| 29 | |
| 30 bool IsProfileCategoryStatEqual(const profiles::ProfileCategoryStat& a, | |
| 31 const profiles::ProfileCategoryStat& b) { | |
| 32 return a.category == b.category && a.count == b.count && | |
| 33 a.success == b.success; | |
| 34 } | |
| 35 | |
| 36 std::string ProfileCategoryStatToString( | |
| 37 const profiles::ProfileCategoryStat& a) { | |
| 38 return base::StringPrintf("category = %s, count = %d, success = %s", | |
| 39 a.category.c_str(), a.count, a.success ? "true" : "false"); | |
| 40 } | |
| 41 | |
| 42 ::testing::AssertionResult AssertionProfileCategoryStatEqual( | |
| 43 const char* actual_expression, | |
| 44 const char* expected_expression, | |
| 45 const profiles::ProfileCategoryStat& actual_value, | |
| 46 const profiles::ProfileCategoryStat& expected_value) { | |
| 47 if (IsProfileCategoryStatEqual(actual_value, expected_value)) { | |
| 48 return ::testing::AssertionSuccess(); | |
| 49 } else { | |
| 50 return ::testing::AssertionFailure() | |
| 51 << "Value of: " << actual_expression | |
| 52 << "\n Actual: " << ProfileCategoryStatToString(actual_value) | |
| 53 << "\nExpected: " << expected_expression | |
| 54 << "\nWhich is: " << ProfileCategoryStatToString(expected_value); | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 ::testing::AssertionResult AssertionProfileCategoryStatsEqual( | |
| 59 const char* actual_expression, | |
| 60 const char* expected_expression, | |
| 61 const profiles::ProfileCategoryStats& actual_value, | |
|
Mike Lerman
2016/01/14 15:21:53
don't use "value", it conveys nothing.
actual_cate
lwchkg
2016/01/16 18:07:50
Acknowledged.
| |
| 62 const profiles::ProfileCategoryStats& expected_value) { | |
|
lwchkg
2016/01/13 17:21:55
Here's some sample output of the function.
e:\chr
Mike Lerman
2016/01/14 15:21:53
Why only print the unmatched rows?? Why not just p
lwchkg
2016/01/16 18:07:50
I see. I'd print out the whole statistics since co
| |
| 63 size_t actual_count = actual_value.size(); | |
| 64 size_t expected_count = expected_value.size(); | |
| 65 std::vector<bool> actual_unused(actual_count, true); | |
| 66 std::vector<bool> expected_unused(expected_count, true); | |
| 67 | |
| 68 bool match_failed = actual_count != expected_count; | |
|
Mike Lerman
2016/01/14 15:21:53
match of what? of counts. Perhaps call this counts
lwchkg
2016/01/16 18:07:51
Looks like I've named the variable incorrectly, so
anthonyvd
2016/01/18 15:47:08
You could probably just add a comment with the abo
lwchkg
2016/01/18 18:01:19
Thanks. So comments will be added in the next patc
lwchkg
2016/02/11 17:13:09
Turns out std::is_permutation() was approved, so I
| |
| 69 for (size_t actual_pos = 0; actual_pos < actual_count; actual_pos++) { | |
| 70 for (size_t expected_pos = 0; expected_pos < expected_count; | |
| 71 expected_pos++) { | |
| 72 if (expected_unused[expected_pos] && | |
| 73 IsProfileCategoryStatEqual(actual_value[actual_pos], | |
| 74 expected_value[expected_pos])) { | |
| 75 actual_unused[actual_pos] = false; | |
| 76 expected_unused[expected_pos] = false; | |
| 77 break; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 if (actual_unused[actual_pos]) | |
| 82 match_failed = true; | |
| 83 } | |
| 84 | |
| 85 if (!match_failed) { | |
| 86 return ::testing::AssertionSuccess(); | |
| 87 } else { | |
| 88 ::testing::AssertionResult result = testing::AssertionFailure(); | |
| 89 result << "ProfileCategoryStats are not equal."; | |
| 90 | |
| 91 result << "\n Actual: " << actual_expression; | |
| 92 bool actual_printed = false; | |
| 93 for (size_t i = 0; i < actual_count; i++) { | |
| 94 if (actual_unused[i]) { | |
| 95 result << "\n" | |
| 96 << (actual_printed ? " " : "Unmatched rows: ") | |
| 97 << ProfileCategoryStatToString(actual_value[i]); | |
| 98 actual_printed = true; | |
| 99 } | |
| 100 } | |
| 101 if (!actual_printed) | |
| 102 result << "(no unmatched rows found in actual value)"; | |
| 103 | |
| 104 | |
| 105 result << "\nExpected: " << expected_expression; | |
| 106 bool expected_printed = false; | |
| 107 for (size_t i = 0; i < expected_count; i++) { | |
| 108 if (expected_unused[i]) { | |
| 109 result << "\n" | |
| 110 << (expected_printed ? " " : "Unmatched rows: ") | |
| 111 << ProfileCategoryStatToString(expected_value[i]); | |
| 112 expected_printed = true; | |
| 113 } | |
| 114 } | |
| 115 if (!expected_printed) | |
| 116 result << "(no unmatched rows found in expected value)"; | |
| 117 | |
| 118 return result; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 class ProfileStatisticsAggregatorState { | |
| 123 public: | |
| 124 void callback(base::RunLoop* run_loop, | |
| 125 profiles::ProfileCategoryStats stats_return) { | |
| 126 size_t oldCount = stats_.size(); | |
| 127 size_t newCount = stats_return.size(); | |
| 128 | |
| 129 EXPECT_LT(oldCount, newCount); | |
| 130 if (oldCount < newCount) { | |
| 131 for (size_t i = 0; i < oldCount; i++) { | |
| 132 // Exisiting statistics must be the same. | |
| 133 EXPECT_PRED_FORMAT2(AssertionProfileCategoryStatEqual, | |
| 134 stats_[i], stats_return[i]); | |
| 135 // The new statistic categories must be different. | |
| 136 for (size_t j = oldCount; j < newCount; j++) | |
| 137 EXPECT_NE(stats_[i].category, stats_return[j].category); | |
| 138 } | |
| 139 | |
| 140 for (size_t j = oldCount; j < newCount; j++) { | |
| 141 EXPECT_EQ(1u, stats_categories.count(stats_return[j].category)); | |
| 142 // Count the number of statistics failures (incrementally). | |
| 143 if (!stats_return[j].success) | |
| 144 num_of_fails_++; | |
| 145 } | |
| 146 stats_ = stats_return; | |
| 147 } | |
| 148 | |
| 149 EXPECT_GE(num_of_stats_categories, newCount); | |
| 150 if (num_of_stats_categories <= newCount) | |
| 151 run_loop->Quit(); | |
| 152 } | |
| 153 | |
| 154 profiles::ProfileCategoryStats GetStats() const { return stats_; } | |
| 155 int GetNumOfFails() const { return num_of_fails_; } | |
| 156 | |
| 157 private: | |
| 158 profiles::ProfileCategoryStats stats_; | |
| 159 int num_of_fails_ = 0; | |
| 160 }; | |
| 161 | |
| 162 void WaitMilliseconds(int time_in_milliseconds) { | |
| 163 base::RunLoop run_loop; | |
| 164 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 165 FROM_HERE, run_loop.QuitClosure(), | |
| 166 base::TimeDelta::FromMilliseconds(time_in_milliseconds)); | |
| 167 run_loop.Run(); | |
| 168 } | |
| 169 | |
| 170 } // namespace | |
| 171 | |
| 172 class ProfileStatisticsBrowserTest : public InProcessBrowserTest { | |
| 173 public: | |
| 174 void SetUpOnMainThread() override { | |
| 175 // Use TestPasswordStore to remove a possible race. Normally the | |
| 176 // PasswordStore does its database manipulation on the DB thread, which | |
| 177 // creates a possible race during navigation. Specifically the | |
| 178 // PasswordManager will ignore any forms in a page if the load from the | |
| 179 // PasswordStore has not completed. | |
| 180 PasswordStoreFactory::GetInstance()->SetTestingFactory( | |
| 181 browser()->profile(), | |
| 182 password_manager::BuildPasswordStore< | |
| 183 content::BrowserContext, password_manager::TestPasswordStore>); | |
| 184 } | |
| 185 }; | |
| 186 | |
| 187 using ProfileStatisticsBrowserDeathTest = ProfileStatisticsBrowserTest; | |
| 188 | |
| 189 IN_PROC_BROWSER_TEST_F(ProfileStatisticsBrowserTest, GatherStatistics) { | |
| 190 Profile* profile = ProfileManager::GetActiveUserProfile(); | |
| 191 ASSERT_TRUE(profile); | |
| 192 | |
| 193 ProfileStatisticsAggregatorState state; | |
| 194 | |
| 195 base::RunLoop run_loop; | |
| 196 profiles::GatherProfileStatistics( | |
| 197 profile, | |
| 198 base::Bind(&ProfileStatisticsAggregatorState::callback, | |
| 199 base::Unretained(&state), &run_loop), | |
| 200 nullptr); | |
| 201 run_loop.Run(); | |
| 202 | |
| 203 EXPECT_EQ(0, state.GetNumOfFails()); | |
| 204 | |
| 205 profiles::ProfileCategoryStats stats = state.GetStats(); | |
| 206 for (const auto& stat : stats) { | |
| 207 if (stat.category != profiles::kProfileStatisticsSettings) | |
| 208 EXPECT_EQ(0, stat.count); | |
| 209 } | |
| 210 | |
| 211 EXPECT_PRED_FORMAT2(AssertionProfileCategoryStatsEqual, stats, | |
| 212 profiles::GetProfileStatisticsFromCache(profile->GetPath())); | |
| 213 } | |
| 214 | |
| 215 IN_PROC_BROWSER_TEST_F(ProfileStatisticsBrowserTest, CloseBrowser) { | |
| 216 Profile* profile = ProfileManager::GetActiveUserProfile(); | |
| 217 ASSERT_TRUE(profile); | |
| 218 | |
| 219 CloseBrowserSynchronously(browser()); | |
| 220 | |
| 221 profiles::ProfileCategoryStats stats; | |
| 222 // Wait for at most 2 seconds for the statistics to be gathered. | |
|
anthonyvd
2016/01/18 15:47:08
This looks to me like it has the potential to be f
lwchkg
2016/01/18 18:01:19
The same topic is still being discussed in patch #
| |
| 223 for (int i = 0; i < 10; i++) { | |
| 224 WaitMilliseconds(200); | |
| 225 stats = profiles::GetProfileStatisticsFromCache(profile->GetPath()); | |
| 226 EXPECT_EQ(num_of_stats_categories, stats.size()); | |
| 227 | |
| 228 bool allSucceed = true; | |
| 229 for (const auto& stat : stats) | |
| 230 allSucceed &= stat.success; | |
| 231 if (allSucceed) | |
| 232 break; | |
| 233 } | |
| 234 | |
| 235 for (const auto& stat : stats) { | |
| 236 EXPECT_EQ(1u, stats_categories.count(stat.category)); | |
| 237 EXPECT_TRUE(stat.success); | |
| 238 if (stat.category != profiles::kProfileStatisticsSettings) | |
| 239 EXPECT_EQ(0, stat.count); | |
| 240 } | |
| 241 // Wait for background tasks to complete, otherwise some warning about | |
| 242 // the failure to post a task will be displayed. | |
| 243 WaitMilliseconds(500); | |
| 244 } | |
| OLD | NEW |