Chromium Code Reviews| Index: chrome/browser/profiles/profile_manager_browsertest.cc |
| diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc |
| index 06f06dc2d8fa4b9e2843c2751ce1d1f706ab6001..d7d160d1b8fff85897353e3f7f62a19cd7e48ede 100644 |
| --- a/chrome/browser/profiles/profile_manager_browsertest.cc |
| +++ b/chrome/browser/profiles/profile_manager_browsertest.cc |
| @@ -36,6 +36,16 @@ |
| #include "testing/gtest/include/gtest/gtest.h" |
| #endif |
| +#if defined(OS_WIN) |
| +#include <AccCtrl.h> |
| +#include <Aclapi.h> |
| +#include "base/callback_forward.h" |
| +#include "base/files/file_util.h" |
| +#include "base/path_service.h" |
| +#include "chrome/common/chrome_paths.h" |
| +#include "chrome/common/chrome_switches.h" |
| +#endif |
|
Peter Kasting
2016/06/04 01:24:25
Nit: There's a lot of stuff in this block and adde
WC Leung
2016/06/04 04:55:22
SGTM
|
| + |
| namespace { |
| const ProfileManager::CreateCallback kOnProfileSwitchDoNothing; |
| @@ -499,3 +509,139 @@ IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, IncognitoProfile) { |
| ->GetFilePath(prefs::kSaveFileDefaultDirectory) |
| .empty()); |
| } |
| + |
| +#if defined(OS_WIN) |
| + |
| +bool AddAceToObjectsSecurityDescriptor(LPTSTR filename, LPTSTR trustee, |
|
brettw
2016/06/03 21:47:24
I'm OK duplicating this code. It's a bit yucky but
Peter Kasting
2016/06/04 01:24:25
It looks to me as if these two are so close that j
WC Leung
2016/06/04 04:55:22
I see. Then I'll do the deduplication.
|
| + DWORD access_rights, ACCESS_MODE access_mode, DWORD inheritance) { |
|
Peter Kasting
2016/06/04 01:24:25
Nit: All lines of args must be indented the same.
WC Leung
2016/06/04 04:55:21
Acknowledged. Anyway, if that deduplication succee
|
| + // Get a pointer to the existing DACL. |
| + ACL* old_dacl = nullptr; |
| + PSECURITY_DESCRIPTOR security_descriptor = nullptr; |
| + DWORD result = GetNamedSecurityInfo(filename, SE_FILE_OBJECT, |
| + DACL_SECURITY_INFORMATION, |
| + nullptr, nullptr, &old_dacl, nullptr, |
| + &security_descriptor); |
| + if (result != ERROR_SUCCESS) { |
| + LOG(WARNING) << "GetNamedSecurityInfo Error " << result; |
|
Peter Kasting
2016/06/04 01:24:25
Are you going to collect and analyze this log data
|
| + } else { |
| + // Initialize an EXPLICIT_ACCESS structure for the new ACE. |
| + EXPLICIT_ACCESS explicit_access; |
| + ZeroMemory(&explicit_access, sizeof(EXPLICIT_ACCESS)); |
| + explicit_access.grfAccessPermissions = access_rights; |
| + explicit_access.grfAccessMode = access_mode; |
| + explicit_access.grfInheritance = inheritance; |
| + explicit_access.Trustee.TrusteeForm = TRUSTEE_IS_NAME; |
| + explicit_access.Trustee.ptstrName = trustee; |
|
Peter Kasting
2016/06/04 01:24:25
Nit: Try to use initializer values if possible, e.
|
| + |
| + // Create a new ACL that merges the new ACE into the existing DACL. |
| + ACL* new_dacl = nullptr; |
| + result = SetEntriesInAcl(1, &explicit_access, old_dacl, &new_dacl); |
| + if (result != ERROR_SUCCESS) { |
| + LOG(WARNING) << "SetEntriesInAcl Error " << result; |
| + } else { |
| + // Attach the new ACL as the object's DACL. |
| + result = SetNamedSecurityInfo(filename, SE_FILE_OBJECT, |
| + DACL_SECURITY_INFORMATION, |
| + nullptr, nullptr, new_dacl, nullptr); |
| + if (result != ERROR_SUCCESS) |
| + LOG(WARNING) << "SetNamedSecurityInfo Error " << result; |
| + } |
| + |
| + if (new_dacl) |
|
Peter Kasting
2016/06/04 01:24:25
Don't conditionalize these LocalFree() calls; it s
WC Leung
2016/06/04 04:55:22
Noted and thanks. https://msdn.microsoft.com/en-us
|
| + LocalFree((HLOCAL)new_dacl); |
|
Peter Kasting
2016/06/04 01:24:25
Consider creating a scoping object that frees thes
WC Leung
2016/06/04 04:55:22
Acknowledged.
|
| + } |
| + |
| + if (security_descriptor) |
| + LocalFree((HLOCAL)security_descriptor); |
| + |
| + return result == ERROR_SUCCESS; |
| +} |
| + |
| +bool RemoveCreateDirectoryPermission(const base::FilePath& path) { |
| + return AddAceToObjectsSecurityDescriptor( |
| + const_cast<wchar_t*>(path.value().c_str()), L"EVERYONE", |
| + FILE_ADD_SUBDIRECTORY, DENY_ACCESS, NO_INHERITANCE); |
| +} |
| + |
| +class ProfileManagerWinBrowserTest : public ProfileManagerBrowserTest { |
| + public: |
| + // Tests may be reported as PASS even if the test has never been run. To |
|
Peter Kasting
2016/06/04 01:24:25
I have no idea what this is talking about :(.
WC Leung
2016/06/04 04:55:22
You've stumpled on a bug in the browser test. :-)
Peter Kasting
2016/06/04 08:01:39
Please understand this bug completely before proce
WC Leung
2016/06/04 15:48:33
Agree that the bug needs more investigation. The p
|
| + // mitigate the issue, a "red flag" is raised for suspectable tests. These |
|
Peter Kasting
2016/06/04 01:24:25
Do you mean "susceptible" or "suspicious"?
WC Leung
2016/06/04 04:55:22
Susceptble. Sorry for wrong spelling.
WC Leung
2016/06/04 17:34:43
Done.
|
| + // tests need to call DropRedFlag() to pass the test. |
| + void DropRedFlag() { red_flag_ = false; } |
| + |
| + protected: |
| + void SetUpCommandLine(base::CommandLine* command_line) override { |
| + command_line->AppendSwitch(switches::kRestoreLastSession); |
| + } |
| + |
| + bool SetUpUserDataDirectory() override { |
| + std::string testname( |
| + testing::UnitTest::GetInstance()->current_test_info()->name()); |
| + if (testname == "LastOpenedProfileMissing") { |
|
brettw
2016/06/03 21:47:24
This seems potentially very confusing since people
WC Leung
2016/06/04 04:55:22
We need to do remove a profile directory and set t
|
| + red_flag_ = true; |
| + |
| + base::FilePath user_data_dir; |
| + if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) |
| + return false; |
| + |
| + base::FilePath dir_to_delete = user_data_dir.AppendASCII("Profile 1"); |
| + return base::DirectoryExists(dir_to_delete) && |
| + DeleteFile(dir_to_delete, true) && |
| + RemoveCreateDirectoryPermission(user_data_dir); |
| + } |
| + return true; |
| + } |
| + |
| + void TearDown() override { |
| + EXPECT_FALSE(red_flag_); |
| + ProfileManagerBrowserTest::TearDown(); |
| + } |
| + |
| + private: |
| + bool red_flag_ = false; |
| +}; |
|
Peter Kasting
2016/06/04 01:24:25
Nit: DISALLOW_COPY_AND_ASSIGN
WC Leung
2016/06/04 04:55:22
Acknowledged.
WC Leung
2016/06/04 17:34:43
Unable to do this in test fixtures, because compil
Peter Kasting
2016/06/04 18:12:31
Why?
WC Leung
2016/06/05 03:04:48
Here's the compiler log:
f:\chromium\src\chrome\b
|
| + |
| +IN_PROC_BROWSER_TEST_F(ProfileManagerWinBrowserTest, |
| + PRE_LastOpenedProfileMissing) { |
|
Peter Kasting
2016/06/04 01:24:25
I'm not terribly familiar with using PRE_ in tests
WC Leung
2016/06/04 04:55:22
The test (PRE_ and non-PRE_ as a whole) do the fol
Peter Kasting
2016/06/04 08:01:39
That didn't really answer my question. Are you sa
WC Leung
2016/06/04 15:48:33
Oh sorry for my bad explanation. What you're sayin
|
| + ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| + ASSERT_TRUE(profile_manager); |
| + |
| + std::vector<base::FilePath> profile_paths; |
| + // Create two additional profile. |
| + for (int i = 0; i < 2; ++i) { |
| + base::FilePath path = profile_manager->GenerateNextProfileDirectoryPath(); |
| + profile_paths.push_back(path); |
| + |
| + base::RunLoop run_loop; |
| + profile_manager->CreateProfileAsync( |
| + path, base::Bind(&OnUnblockOnProfileCreation, &run_loop), |
| + base::string16(), std::string(), std::string()); |
| + |
| + // Run the message loop to allow profile creation to take place; the loop is |
| + // terminated by OnUnblockOnProfileCreation when the profile is created. |
| + run_loop.Run(); |
| + |
| + profiles::SwitchToProfile(path, false, kOnProfileSwitchDoNothing, |
| + ProfileMetrics::SWITCH_PROFILE_ICON); |
| + } |
| + |
| + ASSERT_EQ(base::FilePath(FILE_PATH_LITERAL("Profile 1")), |
| + profile_paths[0].BaseName()); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(ProfileManagerWinBrowserTest, |
| + LastOpenedProfileMissing) { |
| + DropRedFlag(); |
| + |
| + ProfileManager* profile_manager = g_browser_process->profile_manager(); |
|
Peter Kasting
2016/06/04 01:24:25
Why do you need this variable?
WC Leung
2016/06/04 04:55:21
I don't need it, sorry for that. Forgot to remove
|
| + ASSERT_TRUE(profile_manager); |
| + |
| + BrowserList* browser_list = BrowserList::GetInstance(); |
| + EXPECT_EQ(2u, browser_list->size()); |
| + for (const Browser* browser : *browser_list) { |
| + EXPECT_NE(base::FilePath(FILE_PATH_LITERAL("Profile 1")), |
| + browser->profile()->GetPath().BaseName()); |
| + } |
| +} |
| +#endif // defined(OS_WIN) |
|
Peter Kasting
2016/06/04 01:24:25
Nit: Blank line above this, or no blank below the
WC Leung
2016/06/04 04:55:22
Acknowledged.
|