blob: c0391baaefa91106cbbd640593cdb734fc776826 [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/sharing/sharing_fcm_sender.h"
#include <memory>
#include "base/base64.h"
#include "base/callback_list.h"
#include "chrome/browser/sharing/sharing_constants.h"
#include "chrome/browser/sharing/sharing_sync_preference.h"
#include "chrome/browser/sharing/vapid_key_manager.h"
#include "components/gcm_driver/fake_gcm_driver.h"
#include "components/sync_device_info/device_info.h"
#include "components/sync_device_info/fake_device_info_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "crypto/ec_private_key.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using RecipientInfo = chrome_browser_sharing::RecipientInfo;
using SharingMessage = chrome_browser_sharing::SharingMessage;
using namespace testing;
namespace {
const char kMessageId[] = "message_id";
const char kFcmToken[] = "fcm_token";
const char kP256dh[] = "p256dh";
const char kAuthSecret[] = "auth_secret";
const char kSenderFcmToken[] = "sender_fcm_token";
const char kSenderP256dh[] = "sender_p256dh";
const char kSenderAuthSecret[] = "sender_auth_secret";
const char kAuthorizedEntity[] = "authorized_entity";
const int kTtlSeconds = 10;
class FakeGCMDriver : public gcm::FakeGCMDriver {
public:
FakeGCMDriver() {}
~FakeGCMDriver() override {}
void SendWebPushMessage(const std::string& app_id,
const std::string& authorized_entity,
const std::string& p256dh,
const std::string& auth_secret,
const std::string& fcm_token,
crypto::ECPrivateKey* vapid_key,
gcm::WebPushMessage message,
gcm::WebPushCallback callback) override {
app_id_ = app_id;
authorized_entity_ = authorized_entity;
p256dh_ = p256dh;
auth_secret_ = auth_secret;
fcm_token_ = fcm_token;
vapid_key_ = vapid_key;
message_ = std::move(message);
std::move(callback).Run(result_,
base::make_optional<std::string>(kMessageId));
}
const std::string& app_id() { return app_id_; }
const std::string& authorized_entity() { return authorized_entity_; }
const std::string& p256dh() { return p256dh_; }
const std::string& auth_secret() { return auth_secret_; }
const std::string& fcm_token() { return fcm_token_; }
crypto::ECPrivateKey* vapid_key() { return vapid_key_; }
const gcm::WebPushMessage& message() { return message_; }
void set_result(gcm::SendWebPushMessageResult result) { result_ = result; }
private:
std::string app_id_, authorized_entity_, p256dh_, auth_secret_, fcm_token_;
crypto::ECPrivateKey* vapid_key_;
gcm::WebPushMessage message_;
gcm::SendWebPushMessageResult result_;
DISALLOW_COPY_AND_ASSIGN(FakeGCMDriver);
};
class MockVapidKeyManager : public VapidKeyManager {
public:
MockVapidKeyManager() : VapidKeyManager(nullptr) {}
~MockVapidKeyManager() {}
MOCK_METHOD0(GetOrCreateKey, crypto::ECPrivateKey*());
};
class SharingFCMSenderTest : public Test {
public:
void OnMessageSent(SharingSendMessageResult* result_out,
base::Optional<std::string>* message_id_out,
SharingSendMessageResult result,
base::Optional<std::string> message_id) {
*result_out = result;
*message_id_out = std::move(message_id);
}
protected:
SharingFCMSenderTest() {
// TODO: Used fake GCMDriver
sync_prefs_ = std::make_unique<SharingSyncPreference>(
&prefs_, &fake_device_info_sync_service);
sharing_fcm_sender_ = std::make_unique<SharingFCMSender>(
&fake_gcm_driver_,
fake_device_info_sync_service.GetLocalDeviceInfoProvider(),
sync_prefs_.get(), &vapid_key_manager_);
SharingSyncPreference::RegisterProfilePrefs(prefs_.registry());
}
syncer::FakeDeviceInfoSyncService fake_device_info_sync_service;
FakeGCMDriver fake_gcm_driver_;
std::unique_ptr<SharingSyncPreference> sync_prefs_;
std::unique_ptr<SharingFCMSender> sharing_fcm_sender_;
NiceMock<MockVapidKeyManager> vapid_key_manager_;
private:
sync_preferences::TestingPrefServiceSyncable prefs_;
};
} // namespace
struct SharingFCMSenderResultTestData {
const gcm::SendWebPushMessageResult web_push_result;
const SharingSendMessageResult expected_result;
const bool ready_before_send_message;
} kSharingFCMSenderResultTestData[] = {
{gcm::SendWebPushMessageResult::kSuccessful,
SharingSendMessageResult::kSuccessful,
/*ready_before_send_message=*/false},
{gcm::SendWebPushMessageResult::kSuccessful,
SharingSendMessageResult::kSuccessful,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kDeviceGone,
SharingSendMessageResult::kDeviceNotFound,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kNetworkError,
SharingSendMessageResult::kNetworkError,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kPayloadTooLarge,
SharingSendMessageResult::kPayloadTooLarge,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kEncryptionFailed,
SharingSendMessageResult::kInternalError,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kCreateJWTFailed,
SharingSendMessageResult::kInternalError,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kServerError,
SharingSendMessageResult::kInternalError,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kParseResponseFailed,
SharingSendMessageResult::kInternalError,
/*ready_before_send_message=*/true},
{gcm::SendWebPushMessageResult::kVapidKeyInvalid,
SharingSendMessageResult::kInternalError,
/*ready_before_send_message=*/true}};
class SharingFCMSenderResultTest
: public SharingFCMSenderTest,
public testing::WithParamInterface<SharingFCMSenderResultTestData> {};
TEST_P(SharingFCMSenderResultTest, ResultTest) {
sync_prefs_->SetFCMRegistration(SharingSyncPreference::FCMRegistration(
kAuthorizedEntity, base::Time::Now()));
syncer::DeviceInfo* local_device_info =
fake_device_info_sync_service.GetLocalDeviceInfoProvider()
->GetMutableDeviceInfo();
local_device_info->set_sharing_info(syncer::DeviceInfo::SharingInfo(
kSenderFcmToken, kSenderP256dh, kSenderAuthSecret,
std::set<sync_pb::SharingSpecificFields::EnabledFeatures>()));
fake_device_info_sync_service.GetLocalDeviceInfoProvider()->SetReady(
GetParam().ready_before_send_message);
fake_gcm_driver_.set_result(GetParam().web_push_result);
std::unique_ptr<crypto::ECPrivateKey> vapid_key =
crypto::ECPrivateKey::Create();
ON_CALL(vapid_key_manager_, GetOrCreateKey())
.WillByDefault(Return(vapid_key.get()));
syncer::DeviceInfo::SharingInfo target(
kFcmToken, kP256dh, kAuthSecret,
std::set<sync_pb::SharingSpecificFields::EnabledFeatures>());
SharingSendMessageResult result;
base::Optional<std::string> message_id;
SharingMessage sharing_message;
sharing_message.mutable_ping_message();
sharing_fcm_sender_->SendMessageToDevice(
std::move(target), base::TimeDelta::FromSeconds(kTtlSeconds),
std::move(sharing_message),
base::BindOnce(&SharingFCMSenderTest::OnMessageSent,
base::Unretained(this), &result, &message_id));
fake_device_info_sync_service.GetLocalDeviceInfoProvider()->SetReady(true);
EXPECT_EQ(kSharingFCMAppID, fake_gcm_driver_.app_id());
EXPECT_EQ(kAuthorizedEntity, fake_gcm_driver_.authorized_entity());
EXPECT_EQ(kP256dh, fake_gcm_driver_.p256dh());
EXPECT_EQ(kAuthSecret, fake_gcm_driver_.auth_secret());
EXPECT_EQ(kFcmToken, fake_gcm_driver_.fcm_token());
EXPECT_EQ(vapid_key.get(), fake_gcm_driver_.vapid_key());
EXPECT_EQ(kTtlSeconds, fake_gcm_driver_.message().time_to_live);
EXPECT_EQ(gcm::WebPushMessage::Urgency::kHigh,
fake_gcm_driver_.message().urgency);
SharingMessage message_sent;
message_sent.ParseFromString(fake_gcm_driver_.message().payload);
EXPECT_EQ(local_device_info->guid(), message_sent.sender_guid());
EXPECT_TRUE(message_sent.has_ping_message());
EXPECT_EQ(local_device_info->client_name(),
message_sent.sender_device_name());
EXPECT_TRUE(message_sent.has_sender_info());
EXPECT_EQ(kSenderFcmToken, message_sent.sender_info().fcm_token());
EXPECT_EQ(kSenderP256dh, message_sent.sender_info().p256dh());
EXPECT_EQ(kSenderAuthSecret, message_sent.sender_info().auth_secret());
EXPECT_EQ(GetParam().expected_result, result);
EXPECT_EQ(kMessageId, message_id);
}
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
SharingFCMSenderResultTest,
testing::ValuesIn(kSharingFCMSenderResultTestData));