blob: fa5bcc5362be737cd9818342d8b1e4b1eeb0e0ad [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/policy/policy_test_utils.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop_current.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/chrome_screenshot_grabber.h"
#include "chrome/browser/ui/ash/chrome_screenshot_grabber_test_observer.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/safe_search_util.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/policy_constants.h"
#include "components/security_interstitials/content/security_interstitial_page.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/variations/variations_params_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/network_service_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/transport_security_state.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#if defined(OS_CHROMEOS)
#include "ui/snapshot/screenshot_grabber.h"
#endif
using content::BrowserThread;
using testing::_;
using testing::Return;
namespace policy {
const base::FilePath::CharType kTestExtensionsDir[] =
FILE_PATH_LITERAL("extensions");
void GetTestDataDirectory(base::FilePath* test_data_directory) {
ASSERT_TRUE(
base::PathService::Get(chrome::DIR_TEST_DATA, test_data_directory));
}
PolicyTest::PolicyTest() = default;
PolicyTest::~PolicyTest() = default;
void PolicyTest::SetUp() {
InProcessBrowserTest::SetUp();
}
void PolicyTest::SetUpInProcessBrowserTestFixture() {
base::CommandLine::ForCurrentProcess()->AppendSwitch("noerrdialogs");
EXPECT_CALL(provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
}
void PolicyTest::SetUpOnMainThread() {
host_resolver()->AddRule("*", "127.0.0.1");
}
void PolicyTest::SetUpCommandLine(base::CommandLine* command_line) {
variations::testing::VariationParamsManager::AppendVariationParams(
"ReportCertificateErrors", "ShowAndPossiblySend",
{{"sendingThreshold", "1.0"}}, command_line);
}
void PolicyTest::SetScreenshotPolicy(bool enabled) {
PolicyMap policies;
policies.Set(key::kDisableScreenshots, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(!enabled), nullptr);
UpdateProviderPolicy(policies);
}
void PolicyTest::SetRequireCTForTesting(bool required) {
if (content::IsOutOfProcessNetworkService()) {
mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
content::GetNetworkService()->BindTestInterface(
network_service_test.BindNewPipeAndPassReceiver());
network::mojom::NetworkServiceTest::RequireCT required_ct =
required ? network::mojom::NetworkServiceTest::RequireCT::REQUIRE
: network::mojom::NetworkServiceTest::RequireCT::DEFAULT;
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
network_service_test->SetRequireCT(required_ct);
return;
}
base::PostTask(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&net::TransportSecurityState::SetRequireCTForTesting,
required));
}
#if defined(OS_CHROMEOS)
class QuitMessageLoopAfterScreenshot
: public ChromeScreenshotGrabberTestObserver {
public:
explicit QuitMessageLoopAfterScreenshot(base::OnceClosure done)
: done_(std::move(done)) {}
void OnScreenshotCompleted(ui::ScreenshotResult screenshot_result,
const base::FilePath& screenshot_path) override {
base::PostTaskAndReply(FROM_HERE, {BrowserThread::IO}, base::DoNothing(),
std::move(done_));
}
~QuitMessageLoopAfterScreenshot() override {}
private:
base::OnceClosure done_;
};
void PolicyTest::TestScreenshotFile(bool enabled) {
base::RunLoop run_loop;
QuitMessageLoopAfterScreenshot observer_(run_loop.QuitClosure());
ChromeScreenshotGrabber* grabber = ChromeScreenshotGrabber::Get();
grabber->test_observer_ = &observer_;
SetScreenshotPolicy(enabled);
grabber->HandleTakeScreenshotForAllRootWindows();
run_loop.Run();
grabber->test_observer_ = nullptr;
}
#endif // defined(OS_CHROMEOS)
scoped_refptr<const extensions::Extension> PolicyTest::LoadUnpackedExtension(
const base::FilePath::StringType& name) {
base::FilePath extension_path(ui_test_utils::GetTestFilePath(
base::FilePath(kTestExtensionsDir), base::FilePath(name)));
extensions::ChromeTestExtensionLoader loader(browser()->profile());
return loader.LoadExtension(extension_path);
}
void PolicyTest::UpdateProviderPolicy(const PolicyMap& policy) {
PolicyMap policy_with_defaults;
policy_with_defaults.CopyFrom(policy);
#if defined(OS_CHROMEOS)
SetEnterpriseUsersDefaults(&policy_with_defaults);
#endif
provider_.UpdateChromePolicy(policy_with_defaults);
DCHECK(base::MessageLoopCurrent::Get());
base::RunLoop loop;
loop.RunUntilIdle();
}
void PolicyTest::PerformClick(int x, int y) {
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
blink::WebMouseEvent click_event(
blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
click_event.button = blink::WebMouseEvent::Button::kLeft;
click_event.click_count = 1;
click_event.SetPositionInWidget(x, y);
contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(click_event);
click_event.SetType(blink::WebInputEvent::kMouseUp);
contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(click_event);
}
void PolicyTest::SetPolicy(PolicyMap* policies,
const char* key,
std::unique_ptr<base::Value> value) {
if (value) {
policies->Set(key, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::move(value), nullptr);
} else {
policies->Erase(key);
}
}
void PolicyTest::ApplySafeSearchPolicy(
std::unique_ptr<base::Value> legacy_safe_search,
std::unique_ptr<base::Value> google_safe_search,
std::unique_ptr<base::Value> legacy_youtube,
std::unique_ptr<base::Value> youtube_restrict) {
PolicyMap policies;
SetPolicy(&policies, key::kForceSafeSearch, std::move(legacy_safe_search));
SetPolicy(&policies, key::kForceGoogleSafeSearch,
std::move(google_safe_search));
SetPolicy(&policies, key::kForceYouTubeSafetyMode, std::move(legacy_youtube));
SetPolicy(&policies, key::kForceYouTubeRestrict, std::move(youtube_restrict));
UpdateProviderPolicy(policies);
}
#if defined(OS_CHROMEOS)
void PolicyTest::SetEnableFlag(const keyboard::KeyboardEnableFlag& flag) {
auto* keyboard_client = ChromeKeyboardControllerClient::Get();
keyboard_client->SetEnableFlag(flag);
}
void PolicyTest::ClearEnableFlag(const keyboard::KeyboardEnableFlag& flag) {
auto* keyboard_client = ChromeKeyboardControllerClient::Get();
keyboard_client->ClearEnableFlag(flag);
}
#endif // defined(OS_CHROMEOS)
// static
GURL PolicyTest::GetExpectedSearchURL(bool expect_safe_search) {
std::string expected_url("http://google.com/");
if (expect_safe_search) {
expected_url += "?" +
std::string(safe_search_util::kSafeSearchSafeParameter) +
"&" + safe_search_util::kSafeSearchSsuiParameter;
}
return GURL(expected_url);
}
// static
void PolicyTest::CheckSafeSearch(Browser* browser,
bool expect_safe_search,
const std::string& url) {
content::WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
content::TestNavigationObserver observer(web_contents);
ui_test_utils::SendToOmniboxAndSubmit(browser, url);
observer.Wait();
OmniboxEditModel* model =
browser->window()->GetLocationBar()->GetOmniboxView()->model();
EXPECT_TRUE(model->CurrentMatch(nullptr).destination_url.is_valid());
EXPECT_EQ(GetExpectedSearchURL(expect_safe_search), web_contents->GetURL());
}
// static
void PolicyTest::CheckYouTubeRestricted(
int youtube_restrict_mode,
const std::map<GURL, net::HttpRequestHeaders>& urls_requested,
const GURL& url) {
auto iter = urls_requested.find(url);
ASSERT_TRUE(iter != urls_requested.end());
std::string header;
iter->second.GetHeader(safe_search_util::kYouTubeRestrictHeaderName, &header);
if (youtube_restrict_mode == safe_search_util::YOUTUBE_RESTRICT_OFF) {
EXPECT_TRUE(header.empty());
} else if (youtube_restrict_mode ==
safe_search_util::YOUTUBE_RESTRICT_MODERATE) {
EXPECT_EQ(header, safe_search_util::kYouTubeRestrictHeaderValueModerate);
} else if (youtube_restrict_mode ==
safe_search_util::YOUTUBE_RESTRICT_STRICT) {
EXPECT_EQ(header, safe_search_util::kYouTubeRestrictHeaderValueStrict);
}
}
// static
void PolicyTest::CheckAllowedDomainsHeader(
const std::string& allowed_domain,
const std::map<GURL, net::HttpRequestHeaders>& urls_requested,
const GURL& url) {
auto iter = urls_requested.find(url);
ASSERT_TRUE(iter != urls_requested.end());
if (allowed_domain.empty()) {
EXPECT_TRUE(
!iter->second.HasHeader(safe_search_util::kGoogleAppsAllowedDomains));
return;
}
std::string header;
iter->second.GetHeader(safe_search_util::kGoogleAppsAllowedDomains, &header);
EXPECT_EQ(header, allowed_domain);
}
// static
bool PolicyTest::FetchSubresource(content::WebContents* web_contents,
const GURL& url) {
std::string script(
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', '");
script += url.spec() +
"', true);"
"xhr.onload = function (e) {"
" if (xhr.readyState === 4) {"
" window.domAutomationController.send(xhr.status === 200);"
" }"
"};"
"xhr.onerror = function () {"
" window.domAutomationController.send(false);"
"};"
"xhr.send(null)";
bool xhr_result = false;
bool execute_result =
content::ExecuteScriptAndExtractBool(web_contents, script, &xhr_result);
return xhr_result && execute_result;
}
bool PolicyTest::IsShowingInterstitial(content::WebContents* tab) {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
tab);
if (!helper) {
return false;
}
return helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting() !=
nullptr;
}
void PolicyTest::WaitForInterstitial(content::WebContents* tab) {
ASSERT_TRUE(IsShowingInterstitial(tab));
ASSERT_TRUE(WaitForRenderFrameReady(tab->GetMainFrame()));
}
int PolicyTest::IsExtendedReportingCheckboxVisibleOnInterstitial() {
const std::string command = base::StringPrintf(
"var node = document.getElementById('extended-reporting-opt-in');"
"if (node) {"
" window.domAutomationController.send(node.offsetWidth > 0 || "
" node.offsetHeight > 0 ? %d : %d);"
"} else {"
// The node should be present but not visible, so trigger an error
// by sending false if it's not present.
" window.domAutomationController.send(%d);"
"}",
security_interstitials::CMD_TEXT_FOUND,
security_interstitials::CMD_TEXT_NOT_FOUND,
security_interstitials::CMD_ERROR);
content::WebContents* tab =
browser()->tab_strip_model()->GetActiveWebContents();
WaitForInterstitial(tab);
int result = 0;
EXPECT_TRUE(content::ExecuteScriptAndExtractInt(tab->GetMainFrame(), command,
&result));
return result;
}
void PolicyTest::SendInterstitialCommand(
content::WebContents* tab,
security_interstitials::SecurityInterstitialCommand command) {
security_interstitials::SecurityInterstitialTabHelper* helper =
security_interstitials::SecurityInterstitialTabHelper::FromWebContents(
tab);
helper->GetBlockingPageForCurrentlyCommittedNavigationForTesting()
->CommandReceived(base::NumberToString(command));
return;
}
} // namespace policy