blob: f2d83d2c1a4f44b47f5c1b330a9e2d55a8e1455a [file] [log] [blame]
// Copyright 2014 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 <utility>
#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
#include "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
#include "chrome/browser/supervised_user/supervised_user_service.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "components/infobars/core/infobar.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
using content::InterstitialPage;
using content::NavigationController;
using content::NavigationEntry;
using content::WebContents;
namespace {
// Tests the filter mode in which all sites are blocked by default.
class SupervisedUserBlockModeTest : public InProcessBrowserTest {
public:
// Indicates whether the interstitial should proceed or not.
enum InterstitialAction {
INTERSTITIAL_PROCEED,
INTERSTITIAL_DONTPROCEED,
};
SupervisedUserBlockModeTest() : supervised_user_service_(NULL) {}
~SupervisedUserBlockModeTest() override {}
void CheckShownPageIsInterstitial(WebContents* tab) {
CheckShownPage(tab, content::PAGE_TYPE_INTERSTITIAL);
}
void CheckShownPageIsNotInterstitial(WebContents* tab) {
CheckShownPage(tab, content::PAGE_TYPE_NORMAL);
}
// Checks to see if the type of the current page is |page_type|.
void CheckShownPage(WebContents* tab, content::PageType page_type) {
ASSERT_FALSE(tab->IsCrashed());
NavigationEntry* entry = tab->GetController().GetActiveEntry();
ASSERT_TRUE(entry);
ASSERT_EQ(page_type, entry->GetPageType());
}
void SendAccessRequest(WebContents* tab) {
InterstitialPage* interstitial_page = tab->GetInterstitialPage();
ASSERT_TRUE(interstitial_page);
// Get the SupervisedUserInterstitial delegate.
content::InterstitialPageDelegate* delegate =
interstitial_page->GetDelegateForTesting();
// Simulate the click on the "request" button.
delegate->CommandReceived("\"request\"");
}
void GoBack(WebContents* tab) {
InterstitialPage* interstitial_page = tab->GetInterstitialPage();
ASSERT_TRUE(interstitial_page);
// Get the SupervisedUserInterstitial delegate.
content::InterstitialPageDelegate* delegate =
interstitial_page->GetDelegateForTesting();
// Simulate the click on the "back" button.
delegate->CommandReceived("\"back\"");
}
protected:
void SetUpOnMainThread() override {
// Set up the SupervisedUserNavigationObserver manually since the profile
// was not supervised when the browser was created.
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
SupervisedUserNavigationObserver::CreateForWebContents(web_contents);
Profile* profile = browser()->profile();
supervised_user_service_ =
SupervisedUserServiceFactory::GetForProfile(profile);
SupervisedUserSettingsService* supervised_user_settings_service =
SupervisedUserSettingsServiceFactory::GetForProfile(profile);
supervised_user_settings_service->SetLocalSetting(
supervised_users::kContentPackDefaultFilteringBehavior,
scoped_ptr<base::Value>(
new base::FundamentalValue(SupervisedUserURLFilter::BLOCK)));
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// Enable the test server and remap all URLs to it.
ASSERT_TRUE(embedded_test_server()->Start());
std::string host_port = embedded_test_server()->host_port_pair().ToString();
command_line->AppendSwitchASCII(switches::kHostResolverRules,
"MAP *.example.com " + host_port + "," +
"MAP *.new-example.com " + host_port + "," +
"MAP *.a.com " + host_port);
command_line->AppendSwitchASCII(switches::kSupervisedUserId, "asdf");
}
// Acts like a synchronous call to history's QueryHistory. Modified from
// history_querying_unittest.cc.
void QueryHistory(history::HistoryService* history_service,
const std::string& text_query,
const history::QueryOptions& options,
history::QueryResults* results) {
base::RunLoop run_loop;
base::CancelableTaskTracker history_task_tracker;
history_service->QueryHistory(
base::UTF8ToUTF16(text_query),
options,
base::Bind(&SupervisedUserBlockModeTest::QueryHistoryComplete,
base::Unretained(this),
results,
&run_loop),
&history_task_tracker);
run_loop.Run(); // Will go until ...Complete calls Quit.
}
void QueryHistoryComplete(history::QueryResults* new_results,
base::RunLoop* run_loop,
history::QueryResults* results) {
results->Swap(new_results);
run_loop->Quit(); // Will return out to QueryHistory.
}
SupervisedUserService* supervised_user_service_;
};
class MockTabStripModelObserver : public TabStripModelObserver {
public:
explicit MockTabStripModelObserver(TabStripModel* tab_strip)
: tab_strip_(tab_strip) {
tab_strip_->AddObserver(this);
}
~MockTabStripModelObserver() {
tab_strip_->RemoveObserver(this);
}
MOCK_METHOD3(TabClosingAt, void(TabStripModel*, content::WebContents*, int));
private:
TabStripModel* tab_strip_;
};
// Navigates to a blocked URL.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
SendAccessRequestOnBlockedURL) {
GURL test_url("http://www.example.com/simple.html");
ui_test_utils::NavigateToURL(browser(), test_url);
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
CheckShownPageIsInterstitial(tab);
SendAccessRequest(tab);
// TODO(sergiu): Properly check that the access request was sent here.
GoBack(tab);
// Make sure that the tab is still there.
EXPECT_EQ(tab, browser()->tab_strip_model()->GetActiveWebContents());
CheckShownPageIsNotInterstitial(tab);
}
// Navigates to a blocked URL in a new tab. We expect the tab to be closed
// automatically on pressing the "back" button on the interstitial.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest, OpenBlockedURLInNewTab) {
TabStripModel* tab_strip = browser()->tab_strip_model();
WebContents* prev_tab = tab_strip->GetActiveWebContents();
// Open blocked URL in a new tab.
GURL test_url("http://www.example.com/simple.html");
ui_test_utils::NavigateToURLWithDisposition(
browser(), test_url, NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
// Check that we got the interstitial.
WebContents* tab = tab_strip->GetActiveWebContents();
CheckShownPageIsInterstitial(tab);
// On pressing the "back" button, the new tab should be closed, and we should
// get back to the previous active tab.
MockTabStripModelObserver observer(tab_strip);
base::RunLoop run_loop;
EXPECT_CALL(observer,
TabClosingAt(tab_strip, tab, tab_strip->active_index()))
.WillOnce(testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
GoBack(tab);
run_loop.Run();
EXPECT_EQ(prev_tab, tab_strip->GetActiveWebContents());
}
// Tests whether a visit attempt adds a special history entry.
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest,
HistoryVisitRecorded) {
GURL allowed_url("http://www.example.com/simple.html");
scoped_refptr<SupervisedUserURLFilter> filter =
supervised_user_service_->GetURLFilterForUIThread();
// Set the host as allowed.
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
dict->SetBooleanWithoutPathExpansion(allowed_url.host(), true);
SupervisedUserSettingsService* supervised_user_settings_service =
SupervisedUserSettingsServiceFactory::GetForProfile(
browser()->profile());
supervised_user_settings_service->SetLocalSetting(
supervised_users::kContentPackManualBehaviorHosts, std::move(dict));
EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
filter->GetFilteringBehaviorForURL(allowed_url));
EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
filter->GetFilteringBehaviorForURL(allowed_url.GetWithEmptyPath()));
ui_test_utils::NavigateToURL(browser(), allowed_url);
// Navigate to it and check that we don't get an interstitial.
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
CheckShownPageIsNotInterstitial(tab);
// Navigate to a blocked page and go back on the interstitial.
GURL blocked_url("http://www.new-example.com/simple.html");
ui_test_utils::NavigateToURL(browser(), blocked_url);
tab = browser()->tab_strip_model()->GetActiveWebContents();
CheckShownPageIsInterstitial(tab);
GoBack(tab);
// Check that we went back to the first URL and that the manual behaviors
// have not changed.
EXPECT_EQ(allowed_url.spec(), tab->GetURL().spec());
EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
filter->GetFilteringBehaviorForURL(allowed_url.GetWithEmptyPath()));
EXPECT_EQ(SupervisedUserURLFilter::BLOCK,
filter->GetFilteringBehaviorForURL(blocked_url.GetWithEmptyPath()));
// Query the history entry.
history::HistoryService* history_service =
HistoryServiceFactory::GetForProfile(browser()->profile(),
ServiceAccessType::EXPLICIT_ACCESS);
history::QueryOptions options;
history::QueryResults results;
QueryHistory(history_service, "", options, &results);
// Check that the entries have the correct blocked_visit value.
ASSERT_EQ(2u, results.size());
EXPECT_EQ(blocked_url.spec(), results[0].url().spec());
EXPECT_TRUE(results[0].blocked_visit());
EXPECT_EQ(allowed_url.spec(), results[1].url().spec());
EXPECT_FALSE(results[1].blocked_visit());
}
IN_PROC_BROWSER_TEST_F(SupervisedUserBlockModeTest, Unblock) {
GURL test_url("http://www.example.com/simple.html");
ui_test_utils::NavigateToURL(browser(), test_url);
WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
CheckShownPageIsInterstitial(web_contents);
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
// Set the host as allowed.
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
dict->SetBooleanWithoutPathExpansion(test_url.host(), true);
SupervisedUserSettingsService* supervised_user_settings_service =
SupervisedUserSettingsServiceFactory::GetForProfile(
browser()->profile());
supervised_user_settings_service->SetLocalSetting(
supervised_users::kContentPackManualBehaviorHosts, std::move(dict));
scoped_refptr<SupervisedUserURLFilter> filter =
supervised_user_service_->GetURLFilterForUIThread();
EXPECT_EQ(SupervisedUserURLFilter::ALLOW,
filter->GetFilteringBehaviorForURL(test_url.GetWithEmptyPath()));
observer.Wait();
EXPECT_EQ(test_url, web_contents->GetURL());
}
} // namespace