blob: 1677a01230ff16d10809b5d9236a845f1cbcf31e [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 <map>
#include <string>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browsing_data/browsing_data_helper.h"
#include "chrome/browser/browsing_data/browsing_data_remover.h"
#include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
#include "chrome/browser/infobars/infobar_responder.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/notifications/notification_test_util.h"
#include "chrome/browser/notifications/platform_notification_service_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/push_messaging/push_messaging_application_id.h"
#include "chrome/browser/push_messaging/push_messaging_constants.h"
#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
#include "chrome/browser/services/gcm/fake_gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/gcm_driver/gcm_client.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "ui/base/window_open_disposition.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#endif
namespace {
// Class to instantiate on the stack that is meant to be used with
// FakeGCMProfileService. The ::Run() method follows the signature of
// FakeGCMProfileService::UnregisterCallback.
class UnregistrationCallback {
public:
UnregistrationCallback()
: message_loop_runner_(new content::MessageLoopRunner) {}
void Run(const std::string& app_id) {
app_id_ = app_id;
message_loop_runner_->Quit();
}
void WaitUntilSatisfied() {
message_loop_runner_->Run();
}
const std::string& app_id() {
return app_id_;
}
private:
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
std::string app_id_;
};
} // namespace
class PushMessagingBrowserTest : public InProcessBrowserTest {
public:
PushMessagingBrowserTest() : gcm_service_(nullptr) {}
~PushMessagingBrowserTest() override {}
// InProcessBrowserTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kEnablePushMessagePayload);
command_line->AppendSwitch(switches::kEnablePushMessagingHasPermission);
InProcessBrowserTest::SetUpCommandLine(command_line);
}
// InProcessBrowserTest:
void SetUp() override {
https_server_.reset(new net::SpawnedTestServer(
net::SpawnedTestServer::TYPE_HTTPS,
net::BaseTestServer::SSLOptions(
net::BaseTestServer::SSLOptions::CERT_OK),
base::FilePath(FILE_PATH_LITERAL("chrome/test/data/"))));
ASSERT_TRUE(https_server_->Start());
#if defined(ENABLE_NOTIFICATIONS)
notification_manager_.reset(new StubNotificationUIManager);
notification_service()->SetNotificationUIManagerForTesting(
notification_manager());
#endif
InProcessBrowserTest::SetUp();
}
// InProcessBrowserTest:
void SetUpOnMainThread() override {
gcm_service_ = static_cast<gcm::FakeGCMProfileService*>(
gcm::GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
GetBrowser()->profile(), &gcm::FakeGCMProfileService::Build));
gcm_service_->set_collect(true);
push_service_ =
PushMessagingServiceFactory::GetForProfile(GetBrowser()->profile());
LoadTestPage();
InProcessBrowserTest::SetUpOnMainThread();
}
// InProcessBrowserTest:
void TearDown() override {
#if defined(ENABLE_NOTIFICATIONS)
notification_service()->SetNotificationUIManagerForTesting(nullptr);
#endif
InProcessBrowserTest::TearDown();
}
void LoadTestPage(const std::string& path) {
ui_test_utils::NavigateToURL(GetBrowser(), https_server_->GetURL(path));
}
void LoadTestPage() {
LoadTestPage(GetTestURL());
}
bool RunScript(const std::string& script, std::string* result) {
return RunScript(script, result, nullptr);
}
bool RunScript(const std::string& script, std::string* result,
content::WebContents* web_contents) {
if (!web_contents)
web_contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
return content::ExecuteScriptAndExtractString(web_contents->GetMainFrame(),
script,
result);
}
void TryToSubscribeSuccessfully(
const std::string& expected_push_subscription_id);
std::string GetEndpointForSubscriptionId(const std::string& subscription_id) {
return std::string(kPushMessagingEndpoint) + "/" + subscription_id;
}
PushMessagingApplicationId GetServiceWorkerAppId(
int64 service_worker_registration_id);
void SendMessageAndWaitUntilHandled(
const PushMessagingApplicationId& app_id,
const gcm::GCMClient::IncomingMessage& message);
net::SpawnedTestServer* https_server() const { return https_server_.get(); }
gcm::FakeGCMProfileService* gcm_service() const { return gcm_service_; }
#if defined(ENABLE_NOTIFICATIONS)
StubNotificationUIManager* notification_manager() const {
return notification_manager_.get();
}
PlatformNotificationServiceImpl* notification_service() const {
return PlatformNotificationServiceImpl::GetInstance();
}
#endif
PushMessagingServiceImpl* push_service() const { return push_service_; }
protected:
virtual std::string GetTestURL() {
return "files/push_messaging/test.html";
}
virtual Browser* GetBrowser() const { return browser(); }
InfoBarService* GetInfoBarService() {
return InfoBarService::FromWebContents(
GetBrowser()->tab_strip_model()->GetActiveWebContents());
}
private:
scoped_ptr<net::SpawnedTestServer> https_server_;
gcm::FakeGCMProfileService* gcm_service_;
PushMessagingServiceImpl* push_service_;
scoped_ptr<StubNotificationUIManager> notification_manager_;
DISALLOW_COPY_AND_ASSIGN(PushMessagingBrowserTest);
};
class PushMessagingBadManifestBrowserTest : public PushMessagingBrowserTest {
std::string GetTestURL() override {
return "files/push_messaging/test_bad_manifest.html";
}
};
IN_PROC_BROWSER_TEST_F(PushMessagingBadManifestBrowserTest,
SubscribeFailsNotVisibleMessages) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ("AbortError - Registration failed - permission denied",
script_result);
}
void PushMessagingBrowserTest::TryToSubscribeSuccessfully(
const std::string& expected_push_subscription_id) {
std::string script_result;
EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
EXPECT_EQ("ok - service worker registered", script_result);
InfoBarResponder accepting_responder(GetInfoBarService(), true);
EXPECT_TRUE(RunScript("requestNotificationPermission()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
EXPECT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ(GetEndpointForSubscriptionId(expected_push_subscription_id),
script_result);
}
PushMessagingApplicationId PushMessagingBrowserTest::GetServiceWorkerAppId(
int64 service_worker_registration_id) {
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
PushMessagingApplicationId application_id = PushMessagingApplicationId::Get(
GetBrowser()->profile(), origin, service_worker_registration_id);
EXPECT_TRUE(application_id.IsValid());
return application_id;
}
void PushMessagingBrowserTest::SendMessageAndWaitUntilHandled(
const PushMessagingApplicationId& app_id,
const gcm::GCMClient::IncomingMessage& message) {
base::RunLoop run_loop;
push_service()->SetMessageCallbackForTesting(run_loop.QuitClosure());
push_service()->OnMessage(app_id.app_id_guid(), message);
run_loop.Run();
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
SubscribeSuccessNotificationsGranted) {
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
SubscribeSuccessNotificationsPrompt) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
InfoBarResponder accepting_responder(GetInfoBarService(), true);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ(GetEndpointForSubscriptionId("1-0"),
script_result);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
SubscribeFailureNotificationsBlocked) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
InfoBarResponder cancelling_responder(GetInfoBarService(), false);
ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
ASSERT_EQ("permission status - denied", script_result);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ("AbortError - Registration failed - permission denied",
script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, SubscribeFailureNoManifest) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
InfoBarResponder accepting_responder(GetInfoBarService(), true);
ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
ASSERT_EQ("permission status - granted", script_result);
ASSERT_TRUE(RunScript("removeManifest()", &script_result));
ASSERT_EQ("manifest removed", script_result);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ("AbortError - Registration failed - no sender id provided",
script_result);
}
// TODO(johnme): Test subscribing from a worker - see https://crbug.com/437298.
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, SubscribePersisted) {
std::string script_result;
// First, test that Service Worker registration IDs are assigned in order of
// registering the Service Workers, and the (fake) push subscription ids are
// assigned in order of push subscription (even when these orders are
// different).
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id_sw0 = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id_sw0.app_id_guid(), gcm_service()->last_registered_app_id());
LoadTestPage("files/push_messaging/subscope1/test.html");
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
LoadTestPage("files/push_messaging/subscope2/test.html");
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
// Note that we need to reload the page after registering, otherwise
// navigator.serviceWorker.ready is going to be resolved with the parent
// Service Worker which still controls the page.
LoadTestPage("files/push_messaging/subscope2/test.html");
TryToSubscribeSuccessfully("1-1" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id_sw2 = GetServiceWorkerAppId(2LL);
EXPECT_EQ(app_id_sw2.app_id_guid(), gcm_service()->last_registered_app_id());
LoadTestPage("files/push_messaging/subscope1/test.html");
TryToSubscribeSuccessfully("1-2" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id_sw1 = GetServiceWorkerAppId(1LL);
EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id());
// Now test that the Service Worker registration IDs and push subscription IDs
// generated above were persisted to SW storage, by checking that they are
// unchanged despite requesting them in a different order.
// TODO(johnme): Ideally we would restart the browser at this point to check
// they were persisted to disk, but that's not currently possible since the
// test server uses random port numbers for each test (even PRE_Foo and Foo),
// so we wouldn't be able to load the test pages with the same origin.
LoadTestPage("files/push_messaging/subscope1/test.html");
TryToSubscribeSuccessfully("1-2" /* expected_push_subscription_id */);
EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id());
LoadTestPage("files/push_messaging/subscope2/test.html");
TryToSubscribeSuccessfully("1-1" /* expected_push_subscription_id */);
EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id());
LoadTestPage();
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
EXPECT_EQ(app_id_sw1.app_id_guid(), gcm_service()->last_registered_app_id());
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventSuccess) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("false - is not controlled", script_result);
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
gcm::GCMClient::IncomingMessage message;
message.sender_id = "1234567890";
message.data["data"] = "testdata";
push_service()->OnMessage(app_id.app_id_guid(), message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result));
EXPECT_EQ("testdata", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("false - is not controlled", script_result);
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
// Unregister service worker. Sending a message should now fail.
ASSERT_TRUE(RunScript("unregisterServiceWorker()", &script_result));
ASSERT_EQ("service worker unregistration status: true", script_result);
// When the push service will receive it next message, given that there is no
// SW available, it should unregister |app_id|.
UnregistrationCallback callback;
gcm_service()->SetUnregisterCallback(base::Bind(&UnregistrationCallback::Run,
base::Unretained(&callback)));
gcm::GCMClient::IncomingMessage message;
message.sender_id = "1234567890";
message.data["data"] = "testdata";
push_service()->OnMessage(app_id.app_id_guid(), message);
callback.WaitUntilSatisfied();
EXPECT_EQ(app_id.app_id_guid(), callback.app_id());
// No push data should have been received.
ASSERT_TRUE(RunScript("resultQueue.popImmediately()", &script_result));
EXPECT_EQ("null", script_result);
}
#if defined(ENABLE_NOTIFICATIONS)
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
PushEventEnforcesUserVisibleNotification) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("false - is not controlled", script_result);
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
notification_manager()->CancelAll();
ASSERT_EQ(0u, notification_manager()->GetNotificationCount());
// We'll need to specify the web_contents in which to eval script, since we're
// going to run script in a background tab.
content::WebContents* web_contents =
GetBrowser()->tab_strip_model()->GetActiveWebContents();
// If the site is visible in an active tab, we should not force a notification
// to be shown. Try it twice, since we allow one mistake per 10 push events.
gcm::GCMClient::IncomingMessage message;
message.sender_id = "1234567890";
for (int n = 0; n < 2; n++) {
message.data["data"] = "testdata";
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result));
EXPECT_EQ("testdata", script_result);
EXPECT_EQ(0u, notification_manager()->GetNotificationCount());
}
// Open a blank foreground tab so site is no longer visible.
ui_test_utils::NavigateToURLWithDisposition(
GetBrowser(), GURL("about:blank"), NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
// If the Service Worker push event handler does not show a notification, we
// should show a forced one, but only on the 2nd occurrence since we allow one
// mistake per 10 push events.
message.data["data"] = "testdata";
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("testdata", script_result);
EXPECT_EQ(0u, notification_manager()->GetNotificationCount());
message.data["data"] = "testdata";
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("testdata", script_result);
EXPECT_EQ(1u, notification_manager()->GetNotificationCount());
const Notification& forced_notification =
notification_manager()->GetNotificationAt(0);
EXPECT_EQ(kPushMessagingForcedNotificationTag, forced_notification.tag());
EXPECT_TRUE(forced_notification.silent());
// Currently, this notification will stick around until the user or webapp
// explicitly dismisses it (though we may change this later).
message.data["data"] = "shownotification";
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("shownotification", script_result);
EXPECT_EQ(2u, notification_manager()->GetNotificationCount());
notification_manager()->CancelAll();
EXPECT_EQ(0u, notification_manager()->GetNotificationCount());
// However if the Service Worker push event handler shows a notification, we
// should not show a forced one.
message.data["data"] = "shownotification";
for (int n = 0; n < 9; n++) {
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("shownotification", script_result);
EXPECT_EQ(1u, notification_manager()->GetNotificationCount());
EXPECT_EQ("push_test_tag",
notification_manager()->GetNotificationAt(0).tag());
notification_manager()->CancelAll();
}
// Now that 10 push messages in a row have shown notifications, we should
// allow the next one to mistakenly not show a notification.
message.data["data"] = "testdata";
SendMessageAndWaitUntilHandled(app_id, message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("testdata", script_result);
EXPECT_EQ(0u, notification_manager()->GetNotificationCount());
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
PushEventNotificationWithoutEventWaitUntil) {
std::string script_result;
content::WebContents* web_contents =
GetBrowser()->tab_strip_model()->GetActiveWebContents();
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("false - is not controlled", script_result);
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
notification_manager()->SetNotificationAddedCallback(
message_loop_runner->QuitClosure());
gcm::GCMClient::IncomingMessage message;
message.sender_id = "1234567890";
message.data["data"] = "shownotification-without-waituntil";
push_service()->OnMessage(app_id.app_id_guid(), message);
ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
EXPECT_EQ("immediate:shownotification-without-waituntil", script_result);
message_loop_runner->Run();
ASSERT_EQ(1u, notification_manager()->GetNotificationCount());
EXPECT_EQ("push_test_tag",
notification_manager()->GetNotificationAt(0).tag());
// Verify that the renderer process hasn't crashed.
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
}
#endif
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysPrompt) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
ASSERT_EQ("permission status - prompt", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysGranted) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
InfoBarResponder accepting_responder(GetInfoBarService(), true);
ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
EXPECT_EQ("permission status - granted", script_result);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ(GetEndpointForSubscriptionId("1-0"),
script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysDenied) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
InfoBarResponder cancelling_responder(GetInfoBarService(), false);
ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
EXPECT_EQ("permission status - denied", script_result);
ASSERT_TRUE(RunScript("subscribePush()", &script_result));
EXPECT_EQ("AbortError - Registration failed - permission denied",
script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - denied", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnsubscribeSuccess) {
std::string script_result;
EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
EXPECT_EQ("ok - service worker registered", script_result);
// Resolves true if there was a subscription.
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
gcm_service()->AddExpectedUnregisterResponse(gcm::GCMClient::SUCCESS);
ASSERT_TRUE(RunScript("unsubscribePush()", &script_result));
EXPECT_EQ("unsubscribe result: true", script_result);
// Resolves false if there was no longer a subscription.
ASSERT_TRUE(RunScript("unsubscribePush()", &script_result));
EXPECT_EQ("unsubscribe result: false", script_result);
// Doesn't reject if there was a network error (deactivates subscription
// locally anyway).
TryToSubscribeSuccessfully("1-1" /* expected_push_subscription_id */);
gcm_service()->AddExpectedUnregisterResponse(gcm::GCMClient::NETWORK_ERROR);
ASSERT_TRUE(RunScript("unsubscribePush()", &script_result));
EXPECT_EQ("unsubscribe result: true", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
// Doesn't reject if there were other push service errors (deactivates
// subscription locally anyway).
TryToSubscribeSuccessfully("1-2" /* expected_push_subscription_id */);
gcm_service()->AddExpectedUnregisterResponse(
gcm::GCMClient::INVALID_PARAMETER);
ASSERT_TRUE(RunScript("unsubscribePush()", &script_result));
EXPECT_EQ("unsubscribe result: true", script_result);
// Unsubscribing (with an existing reference to a PushSubscription), after
// unregistering the Service Worker, just means push subscription isn't found.
TryToSubscribeSuccessfully("1-3" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("unregisterServiceWorker()", &script_result));
ASSERT_EQ("service worker unregistration status: true", script_result);
ASSERT_TRUE(RunScript("unsubscribePush()", &script_result));
EXPECT_EQ("unsubscribe result: false", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
GlobalResetPushPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GetBrowser()->profile()->GetHostContentSettingsMap()->
ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - prompt", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
LocalResetPushPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::FromURLNoWildcard(origin),
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
std::string(),
CONTENT_SETTING_DEFAULT);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - prompt", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
DenyPushPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::FromURLNoWildcard(origin),
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
std::string(),
CONTENT_SETTING_BLOCK);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - denied", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
GlobalResetNotificationsPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GetBrowser()->profile()->GetHostContentSettingsMap()->
ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - prompt", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
LocalResetNotificationsPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_DEFAULT);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - prompt", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
DenyNotificationsPermissionUnsubscribes) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
message_loop_runner->QuitClosure());
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_BLOCK);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - denied", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("false - not subscribed", script_result);
}
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
GrantAlreadyGrantedPermissionDoesNotUnsubscribe) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
base::BarrierClosure(2, message_loop_runner->QuitClosure()));
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_ALLOW);
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::FromURLNoWildcard(origin),
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
std::string(),
CONTENT_SETTING_ALLOW);
message_loop_runner->Run();
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
}
// This test is testing some non-trivial content settings rules and make sure
// that they are respected with regards to automatic unsubscription. In other
// words, it checks that the push service does not end up unsubscribing origins
// that have push permission with some non-common rules.
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
AutomaticUnsubscriptionFollowsContentSettingRules) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
scoped_refptr<content::MessageLoopRunner> message_loop_runner =
new content::MessageLoopRunner;
push_service()->SetContentSettingChangedCallbackForTesting(
base::BarrierClosure(4, message_loop_runner->QuitClosure()));
GURL origin = https_server()->GetURL(std::string()).GetOrigin();
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_ALLOW);
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromString("https://*"),
ContentSettingsPattern::FromString("https://*"),
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
std::string(),
CONTENT_SETTING_ALLOW);
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_DEFAULT);
GetBrowser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::FromURLNoWildcard(origin),
CONTENT_SETTINGS_TYPE_PUSH_MESSAGING,
std::string(),
CONTENT_SETTING_DEFAULT);
message_loop_runner->Run();
// The two first rules should give |origin| the permission to use Push even
// if the rules it used to have have been reset.
// The Push service should not unsubcribe |origin| because at no point it was
// left without permission to use Push.
ASSERT_TRUE(RunScript("permissionState()", &script_result));
EXPECT_EQ("permission status - granted", script_result);
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
}
// Checks that automatically unsubscribing due to a revoked permission is
// handled well if the sender ID needed to unsubscribe was already deleted.
IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
ResetPushPermissionAfterClearingSiteData) {
std::string script_result;
TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
PushMessagingApplicationId app_id = GetServiceWorkerAppId(0LL);
EXPECT_EQ(app_id.app_id_guid(), gcm_service()->last_registered_app_id());
PushMessagingApplicationId stored_app_id = PushMessagingApplicationId::Get(
GetBrowser()->profile(), app_id.app_id_guid());
EXPECT_TRUE(stored_app_id.IsValid());
// Simulate a user clearing site data (including Service Workers, crucially).
BrowsingDataRemover* remover =
BrowsingDataRemover::CreateForUnboundedRange(GetBrowser()->profile());
BrowsingDataRemoverCompletionObserver observer(remover);
remover->Remove(BrowsingDataRemover::REMOVE_SITE_DATA,
BrowsingDataHelper::UNPROTECTED_WEB);
observer.BlockUntilCompletion();
// BrowsingDataRemover deletes itself.
base::RunLoop run_loop;
push_service()->SetContentSettingChangedCallbackForTesting(
run_loop.QuitClosure());
// This shouldn't (asynchronously) cause a DCHECK.
// TODO(johnme): Get this test running on Android, which has a different
// codepath due to sender_id being required for unsubscribing there.
GetBrowser()->profile()->GetHostContentSettingsMap()->
ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
run_loop.Run();
// app_id should no longer be stored in prefs
PushMessagingApplicationId stored_app_id2 = PushMessagingApplicationId::Get(
GetBrowser()->profile(), app_id.app_id_guid());
EXPECT_FALSE(stored_app_id2.IsValid());
}
class PushMessagingIncognitoBrowserTest : public PushMessagingBrowserTest {
public:
~PushMessagingIncognitoBrowserTest() override {}
// PushMessagingBrowserTest:
void SetUpOnMainThread() override {
incognito_browser_ = CreateIncognitoBrowser();
PushMessagingBrowserTest::SetUpOnMainThread();
}
Browser* GetBrowser() const override { return incognito_browser_; }
private:
Browser* incognito_browser_ = nullptr;
};
// Regression test for https://crbug.com/476474
IN_PROC_BROWSER_TEST_F(PushMessagingIncognitoBrowserTest,
IncognitoGetSubscriptionDoesNotHang) {
ASSERT_TRUE(GetBrowser()->profile()->IsOffTheRecord());
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
// In Incognito mode the promise returned by getSubscription should not hang,
// it should just fulfill with null.
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
ASSERT_EQ("false - not subscribed", script_result);
}