blob: 18249f8ef7d79d6c6f401800645e5902da9190fb [file] [log] [blame]
// Copyright 2013 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/printing/cloud_print/privet_notifications.h"
#include <memory>
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/notifications/notification_test_util.h"
#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h"
#include "chrome/browser/printing/cloud_print/privet_http_impl.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::StrictMock;
using ::testing::_;
using ::testing::SaveArg;
namespace cloud_print {
namespace {
const char kExampleDeviceName[] = "test._privet._tcp.local";
const char kExampleDeviceHumanName[] = "Test device";
const char kExampleDeviceDescription[] = "Testing testing";
const char kExampleDeviceID[] = "__test__id";
const char kDeviceInfoURL[] = "http://1.2.3.4:8080/privet/info";
const char kInfoResponseUptime20[] = "{\"uptime\": 20}";
const char kInfoResponseUptime3600[] = "{\"uptime\": 3600}";
const char kInfoResponseNoUptime[] = "{}";
class MockPrivetNotificationsListenerDeleagate
: public PrivetNotificationsListener::Delegate {
public:
MOCK_METHOD2(PrivetNotify, void(int devices_active, bool added));
MOCK_METHOD0(PrivetRemoveNotification, void());
};
class MockPrivetHttpFactory : public PrivetHTTPAsynchronousFactory {
public:
class MockResolution : public PrivetHTTPResolution {
public:
MockResolution(const std::string& name,
net::URLRequestContextGetter* request_context)
: name_(name), request_context_(request_context) {}
~MockResolution() override {}
void Start(const net::HostPortPair& address,
const ResultCallback& callback) override {
callback.Run(std::unique_ptr<PrivetHTTPClient>(new PrivetHTTPClientImpl(
name_, net::HostPortPair("1.2.3.4", 8080), request_context_.get())));
}
void Start(const ResultCallback& callback) override {
Start(net::HostPortPair(), callback);
}
const std::string& GetName() override { return name_; }
private:
std::string name_;
scoped_refptr<net::URLRequestContextGetter> request_context_;
};
explicit MockPrivetHttpFactory(net::URLRequestContextGetter* request_context)
: request_context_(request_context) {}
std::unique_ptr<PrivetHTTPResolution> CreatePrivetHTTP(
const std::string& name) override {
return base::MakeUnique<MockResolution>(name, request_context_.get());
}
private:
scoped_refptr<net::URLRequestContextGetter> request_context_;
};
class PrivetNotificationsListenerTest : public testing::Test {
public:
PrivetNotificationsListenerTest()
: request_context_(new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get())) {
notification_listener_.reset(new PrivetNotificationsListener(
std::unique_ptr<PrivetHTTPAsynchronousFactory>(
new MockPrivetHttpFactory(request_context_.get())),
&mock_delegate_));
description_.name = kExampleDeviceHumanName;
description_.description = kExampleDeviceDescription;
}
virtual ~PrivetNotificationsListenerTest() {}
bool SuccessfulResponseToInfo(const std::string& response) {
net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
if (!fetcher || fetcher->GetOriginalURL() != kDeviceInfoURL)
return false;
fetcher->SetResponseString(response);
fetcher->set_status(
net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
fetcher->set_response_code(200);
fetcher->delegate()->OnURLFetchComplete(fetcher);
return true;
}
protected:
StrictMock<MockPrivetNotificationsListenerDeleagate> mock_delegate_;
std::unique_ptr<PrivetNotificationsListener> notification_listener_;
base::MessageLoop message_loop_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
net::TestURLFetcherFactory fetcher_factory_;
DeviceDescription description_;
};
TEST_F(PrivetNotificationsListenerTest, DisappearReappearTest) {
EXPECT_CALL(mock_delegate_, PrivetNotify(1, true));
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_TRUE(SuccessfulResponseToInfo(kInfoResponseUptime20));
EXPECT_CALL(mock_delegate_, PrivetRemoveNotification());
notification_listener_->DeviceRemoved(kExampleDeviceName);
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
description_.id = kExampleDeviceID;
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
}
TEST_F(PrivetNotificationsListenerTest, RegisterTest) {
EXPECT_CALL(mock_delegate_, PrivetNotify(1, true));
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_TRUE(SuccessfulResponseToInfo(kInfoResponseUptime20));
EXPECT_CALL(mock_delegate_, PrivetRemoveNotification());
description_.id = kExampleDeviceID;
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
}
TEST_F(PrivetNotificationsListenerTest, RepeatedNotification) {
EXPECT_CALL(mock_delegate_, PrivetNotify(1, true));
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_TRUE(SuccessfulResponseToInfo(kInfoResponseUptime20));
EXPECT_CALL(mock_delegate_, PrivetNotify(_, _)).Times(0);
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_CALL(mock_delegate_, PrivetRemoveNotification());
notification_listener_->DeviceRemoved(kExampleDeviceName);
EXPECT_CALL(mock_delegate_, PrivetNotify(_, _)).Times(0);
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_CALL(mock_delegate_, PrivetRemoveNotification()).Times(0);
notification_listener_->DeviceRemoved(kExampleDeviceName);
}
TEST_F(PrivetNotificationsListenerTest, HighUptimeTest) {
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
EXPECT_TRUE(SuccessfulResponseToInfo(kInfoResponseUptime3600));
description_.id = kExampleDeviceID;
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
}
TEST_F(PrivetNotificationsListenerTest, HTTPErrorTest) {
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
fetcher->set_status(
net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
fetcher->set_response_code(200);
fetcher->delegate()->OnURLFetchComplete(fetcher);
}
TEST_F(PrivetNotificationsListenerTest, DictionaryErrorTest) {
notification_listener_->DeviceChanged(kExampleDeviceName, description_);
SuccessfulResponseToInfo(kInfoResponseNoUptime);
}
class TestPrivetNotificationService;
class TestPrivetNotificationDelegate : public PrivetNotificationDelegate {
public:
TestPrivetNotificationDelegate(TestPrivetNotificationService* service,
Profile* profile)
: PrivetNotificationDelegate(profile), service_(service) {}
private:
// Refcounted.
~TestPrivetNotificationDelegate() override {}
// PrivetNotificationDelegate:
void OpenTab(const GURL& url) override;
void DisableNotifications() override;
TestPrivetNotificationService* const service_;
DISALLOW_COPY_AND_ASSIGN(TestPrivetNotificationDelegate);
};
class TestPrivetNotificationService : public PrivetNotificationService {
public:
explicit TestPrivetNotificationService(Profile* profile)
: PrivetNotificationService(profile) {}
~TestPrivetNotificationService() override {}
const GURL& open_tab_url() const { return open_tab_url_; }
size_t open_tab_count() const { return open_tab_count_; }
size_t disable_notifications_count() const {
return disable_notifications_count_;
}
void OpenTab(const GURL& url) {
open_tab_url_ = url;
++open_tab_count_;
}
void DisableNotifications() { ++disable_notifications_count_; }
private:
// PrivetNotificationService:
PrivetNotificationDelegate* CreateNotificationDelegate(
Profile* profile) override {
return new TestPrivetNotificationDelegate(this, profile);
}
GURL open_tab_url_;
size_t open_tab_count_ = 0;
size_t disable_notifications_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(TestPrivetNotificationService);
};
void TestPrivetNotificationDelegate::OpenTab(const GURL& url) {
service_->OpenTab(url);
}
void TestPrivetNotificationDelegate::DisableNotifications() {
service_->DisableNotifications();
}
class PrivetNotificationsNotificationTest : public testing::Test {
public:
PrivetNotificationsNotificationTest() {}
~PrivetNotificationsNotificationTest() override {}
void SetUp() override {
testing::Test::SetUp();
profile_manager_ = base::MakeUnique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(profile_manager_->SetUp());
profile_ = profile_manager_->CreateTestingProfile("test-user");
TestingBrowserProcess::GetGlobal()->SetNotificationUIManager(
base::MakeUnique<StubNotificationUIManager>());
}
void TearDown() override {
profile_manager_.reset();
testing::Test::TearDown();
}
protected:
StubNotificationUIManager* ui_manager() const {
return static_cast<StubNotificationUIManager*>(
TestingBrowserProcess::GetGlobal()->notification_ui_manager());
}
Profile* profile() { return profile_; }
private:
// The thread bundle must be first so it is destroyed last.
content::TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<TestingProfileManager> profile_manager_;
Profile* profile_;
DISALLOW_COPY_AND_ASSIGN(PrivetNotificationsNotificationTest);
};
TEST_F(PrivetNotificationsNotificationTest, AddToCloudPrint) {
TestPrivetNotificationService service(profile());
service.PrivetNotify(1 /* devices_active */, true /* added */);
ASSERT_EQ(1U, ui_manager()->GetNotificationCount());
const auto& notification = ui_manager()->GetNotificationAt(0);
notification.ButtonClick(0 /* add */);
EXPECT_EQ("chrome://devices/", service.open_tab_url().spec());
EXPECT_EQ(1U, service.open_tab_count());
EXPECT_EQ(0U, service.disable_notifications_count());
EXPECT_EQ(0U, ui_manager()->GetNotificationCount());
}
TEST_F(PrivetNotificationsNotificationTest, DontShowAgain) {
TestPrivetNotificationService service(profile());
service.PrivetNotify(1 /* devices_active */, true /* added */);
ASSERT_EQ(1U, ui_manager()->GetNotificationCount());
const auto& notification = ui_manager()->GetNotificationAt(0);
notification.ButtonClick(1 /* don't show again */);
EXPECT_EQ("", service.open_tab_url().spec());
EXPECT_EQ(0U, service.open_tab_count());
EXPECT_EQ(1U, service.disable_notifications_count());
EXPECT_EQ(0U, ui_manager()->GetNotificationCount());
}
} // namespace
} // namespace cloud_print