| Index: components/gcm_driver/gcm_client_impl_unittest.cc
|
| diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
|
| index 827a6056d468ff5ed8c453cc1b578ccfa889cf69..7802fe9ffa3f8d3f8ea7578f4a0bfa3c9566b477 100644
|
| --- a/components/gcm_driver/gcm_client_impl_unittest.cc
|
| +++ b/components/gcm_driver/gcm_client_impl_unittest.cc
|
| @@ -15,8 +15,13 @@
|
| #include "base/files/scoped_temp_dir.h"
|
| #include "base/macros.h"
|
| #include "base/memory/ptr_util.h"
|
| +#include "base/metrics/field_trial.h"
|
| +#include "base/metrics/field_trial_param_associator.h"
|
| +#include "base/metrics/field_trial_params.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/test/histogram_tester.h"
|
| +#include "base/test/mock_entropy_provider.h"
|
| +#include "base/test/scoped_feature_list.h"
|
| #include "base/test/test_mock_time_task_runner.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "base/time/clock.h"
|
| @@ -268,6 +273,7 @@ class GCMClientImplTest : public testing::Test,
|
| void SetUp() override;
|
|
|
| void SetUpUrlFetcherFactory();
|
| + void InitializeFieldTrials(int messages_to_send);
|
|
|
| void BuildGCMClient(base::TimeDelta clock_step);
|
| void InitializeGCMClient();
|
| @@ -309,8 +315,10 @@ class GCMClientImplTest : public testing::Test,
|
| void OnSendFinished(const std::string& app_id,
|
| const std::string& message_id,
|
| GCMClient::Result result) override {}
|
| - void OnMessageReceived(const std::string& registration_id,
|
| - const IncomingMessage& message) override;
|
| + void OnMessageReceived(
|
| + const std::string& registration_id,
|
| + const IncomingMessage& message,
|
| + const MessageReceiptCallback& optional_receipt_callback) override;
|
| void OnMessagesDeleted(const std::string& app_id) override;
|
| void OnMessageSendError(
|
| const std::string& app_id,
|
| @@ -397,6 +405,10 @@ class GCMClientImplTest : public testing::Test,
|
| return task_runner_.get();
|
| }
|
|
|
| + void set_successful_receipt_generation(bool successful_receipt_generation) {
|
| + successful_receipt_generation_ = successful_receipt_generation;
|
| + }
|
| +
|
| private:
|
| // Must be declared first so that it is destroyed last. Injected to
|
| // GCM client.
|
| @@ -412,6 +424,9 @@ class GCMClientImplTest : public testing::Test,
|
| GCMClient::SendErrorDetails last_error_details_;
|
| base::Time last_token_fetch_time_;
|
| std::vector<AccountMapping> last_account_mappings_;
|
| + base::test::ScopedFeatureList scoped_feature_list_;
|
| + std::unique_ptr<base::FieldTrialList> field_trial_list_;
|
| + bool successful_receipt_generation_ = false;
|
|
|
| std::unique_ptr<GCMClientImpl> gcm_client_;
|
|
|
| @@ -427,11 +442,12 @@ class GCMClientImplTest : public testing::Test,
|
| GCMClientImplTest::GCMClientImplTest()
|
| : last_event_(NONE),
|
| last_result_(GCMClient::UNKNOWN_ERROR),
|
| + field_trial_list_(base::MakeUnique<base::FieldTrialList>(
|
| + base::MakeUnique<base::MockEntropyProvider>())),
|
| task_runner_(new base::TestMockTimeTaskRunner),
|
| task_runner_handle_(task_runner_),
|
| url_request_context_getter_(
|
| - new net::TestURLRequestContextGetter(task_runner_)) {
|
| -}
|
| + new net::TestURLRequestContextGetter(task_runner_)) {}
|
|
|
| GCMClientImplTest::~GCMClientImplTest() {}
|
|
|
| @@ -451,6 +467,34 @@ void GCMClientImplTest::SetUpUrlFetcherFactory() {
|
| url_fetcher_factory_.set_remove_fetcher_on_delete(true);
|
| }
|
|
|
| +void GCMClientImplTest::InitializeFieldTrials(int messages_to_send) {
|
| + const std::string kTrialName = "TestGCMMessageReceipts";
|
| + const std::string kGroupName = "UnusedName";
|
| + // kFeatureName and kParam name are also defined in gcm_client_impl.cc.
|
| + const std::string kFeatureName = "GCMMessageReceiptsFeature";
|
| + const std::string kParamName = "message_receipts_to_send";
|
| +
|
| + // Cleanup any old field trial state and reinitialize.
|
| + field_trial_list_.reset();
|
| + field_trial_list_ = base::MakeUnique<base::FieldTrialList>(
|
| + base::MakeUnique<base::MockEntropyProvider>());
|
| + base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
|
| +
|
| + // Create a field trial with message receipts set to messages_to_send.
|
| + scoped_refptr<base::FieldTrial> trial =
|
| + base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
|
| + std::map<std::string, std::string> trial_params;
|
| + trial_params[kParamName] = base::IntToString(messages_to_send);
|
| + base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
|
| + kTrialName, kGroupName, trial_params);
|
| +
|
| + // Create a FeatureList and add the new trial to the list.
|
| + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
|
| + feature_list->RegisterFieldTrialOverride(
|
| + kFeatureName, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
|
| + scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
|
| +}
|
| +
|
| void GCMClientImplTest::PumpLoopUntilIdle() {
|
| task_runner_->RunUntilIdle();
|
| }
|
| @@ -616,11 +660,17 @@ void GCMClientImplTest::OnGCMReady(
|
| last_token_fetch_time_ = last_token_fetch_time;
|
| }
|
|
|
| -void GCMClientImplTest::OnMessageReceived(const std::string& registration_id,
|
| - const IncomingMessage& message) {
|
| +void GCMClientImplTest::OnMessageReceived(
|
| + const std::string& registration_id,
|
| + const IncomingMessage& message,
|
| + const MessageReceiptCallback& optional_receipt_callback) {
|
| last_event_ = MESSAGE_RECEIVED;
|
| last_app_id_ = registration_id;
|
| last_message_ = message;
|
| +
|
| + // If receipt sending is enabled, then send success.
|
| + if (successful_receipt_generation_)
|
| + optional_receipt_callback.Run(GCMMessageStatus::GCM_SUCCESS);
|
| }
|
|
|
| void GCMClientImplTest::OnRegisterFinished(
|
| @@ -936,6 +986,9 @@ TEST_F(GCMClientImplTest, DispatchDownstreamMessage) {
|
| EXPECT_TRUE(message3.IsValid());
|
| ReceiveMessageFromMCS(message3);
|
|
|
| + // TODO(harkness): Add a check for invalid app handler once the
|
| + // DefaultAppHandler is removed.
|
| +
|
| EXPECT_NE(MESSAGE_RECEIVED, last_event());
|
| EXPECT_NE(kExtensionAppId, last_app_id());
|
| }
|
| @@ -1772,6 +1825,10 @@ TEST_F(GCMClientInstanceIDTest, DeleteAllTokensBeforeGetAnyToken) {
|
| }
|
|
|
| TEST_F(GCMClientInstanceIDTest, DispatchDownstreamMessageWithoutSubtype) {
|
| + // Initialize a field trial for sending message receipts and set the messages
|
| + // to send to 2 = ALL.
|
| + InitializeFieldTrials(2);
|
| +
|
| AddInstanceID(kExtensionAppId, kInstanceID);
|
| GetToken(kExtensionAppId, kSender, kScope);
|
| ASSERT_NO_FATAL_FAILURE(CompleteRegistration("token1"));
|
| @@ -1789,6 +1846,24 @@ TEST_F(GCMClientInstanceIDTest, DispatchDownstreamMessageWithoutSubtype) {
|
|
|
| EXPECT_NE(MESSAGE_RECEIVED, last_event());
|
|
|
| + // Check that the last message sent was a message receipt for a failed message
|
| + // and that it had the values expected.
|
| + mcs_proto::DataMessageStanza stanza =
|
| + mcs_client()->last_data_message_stanza();
|
| + EXPECT_EQ(kExtensionAppId, stanza.category());
|
| + const auto& app_data = stanza.app_data();
|
| + ASSERT_EQ(3, app_data.size());
|
| + for (const auto& pair : app_data) {
|
| + if (pair.key() == "message_id")
|
| + EXPECT_EQ("", pair.value());
|
| + else if (pair.key() == "status")
|
| + EXPECT_EQ("2", pair.value());
|
| + else if (pair.key() == "message_type")
|
| + EXPECT_EQ("message_receipt", pair.value());
|
| + else
|
| + FAIL() << "Unexpected key: " << pair.key();
|
| + }
|
| +
|
| reset_last_event();
|
|
|
| // Message for kSender will be received.
|
| @@ -1832,7 +1907,110 @@ TEST_F(GCMClientInstanceIDTest, DispatchDownstreamMessageWithoutSubtype) {
|
| EXPECT_NE(kExtensionAppId, last_app_id());
|
| }
|
|
|
| +// Do not initialize a FieldTrial for sending receipts. Default state of the
|
| +// field trial should be SEND_NONE, so check that no receipt was sent.
|
| +TEST_F(GCMClientInstanceIDTest, ReceiptFieldTrialTestingSendNone) {
|
| + AddInstanceID(kExtensionAppId, kInstanceID);
|
| + GetToken(kExtensionAppId, kSender, kScope);
|
| + ASSERT_NO_FATAL_FAILURE(CompleteRegistration("token1"));
|
| +
|
| + std::map<std::string, std::string> expected_data;
|
| +
|
| + // Message for kSender with a subtype will be dropped and would cause an error
|
| + // receipt to be generated.
|
| + MCSMessage message0(BuildDownstreamMessage(
|
| + kSender, kProductCategoryForSubtypes, kExtensionAppId /* subtype */,
|
| + expected_data, std::string() /* raw_data */));
|
| + EXPECT_TRUE(message0.IsValid());
|
| + ReceiveMessageFromMCS(message0);
|
| +
|
| + EXPECT_NE(MESSAGE_RECEIVED, last_event());
|
| +
|
| + // The only way to check that no messages were sent is to check that the tag
|
| + // is still the default value.
|
| + EXPECT_EQ(MCSProtoTag::kNumProtoTypes, mcs_client()->last_message_tag());
|
| +}
|
| +
|
| +TEST_F(GCMClientInstanceIDTest, ReceiptFieldTrialTestingSendAll) {
|
| + // Initialize a field trial for sending message receipts and set the messages
|
| + // to send to 2 = ALL.
|
| + InitializeFieldTrials(2);
|
| + set_successful_receipt_generation(true);
|
| +
|
| + AddInstanceID(kExtensionAppId, kInstanceID);
|
| + GetToken(kExtensionAppId, kSender, kScope);
|
| + ASSERT_NO_FATAL_FAILURE(CompleteRegistration("token1"));
|
| +
|
| + std::map<std::string, std::string> expected_data;
|
| +
|
| + // Message for kSender will be received.
|
| + MCSMessage message1(BuildDownstreamMessage(
|
| + kSender, kExtensionAppId, std::string() /* subtype */, expected_data,
|
| + std::string() /* raw_data */));
|
| + EXPECT_TRUE(message1.IsValid());
|
| + ReceiveMessageFromMCS(message1);
|
| +
|
| + EXPECT_EQ(MESSAGE_RECEIVED, last_event());
|
| + EXPECT_EQ(kExtensionAppId, last_app_id());
|
| + EXPECT_EQ(expected_data.size(), last_message().data.size());
|
| + EXPECT_EQ(expected_data, last_message().data);
|
| + EXPECT_EQ(kSender, last_message().sender_id);
|
| +
|
| + // Check that the last message sent was a message receipt for a successful
|
| + // message and that it had the values expected.
|
| + mcs_proto::DataMessageStanza stanza =
|
| + mcs_client()->last_data_message_stanza();
|
| + EXPECT_EQ(kExtensionAppId, stanza.category());
|
| + const auto& app_data = stanza.app_data();
|
| + ASSERT_EQ(3, app_data.size());
|
| + for (const auto& pair : app_data) {
|
| + if (pair.key() == "message_id")
|
| + EXPECT_EQ("", pair.value());
|
| + else if (pair.key() == "status")
|
| + EXPECT_EQ("1", pair.value()); // Status should be GCM_SUCCESS = 1.
|
| + else if (pair.key() == "message_type")
|
| + EXPECT_EQ("message_receipt", pair.value());
|
| + else
|
| + FAIL() << "Unexpected key: " << pair.key();
|
| + }
|
| +}
|
| +
|
| +TEST_F(GCMClientInstanceIDTest, ReceiptFieldTrialTestingSendFailures) {
|
| + // Initialize a field trial for sending message receipts and set the messages
|
| + // to send to 1 = SEND_FAILURES. Then when a successful message generates a
|
| + // receipt, it should not be sent.
|
| + InitializeFieldTrials(1);
|
| + set_successful_receipt_generation(true);
|
| +
|
| + AddInstanceID(kExtensionAppId, kInstanceID);
|
| + GetToken(kExtensionAppId, kSender, kScope);
|
| + ASSERT_NO_FATAL_FAILURE(CompleteRegistration("token1"));
|
| +
|
| + std::map<std::string, std::string> expected_data;
|
| +
|
| + // Message for kSender will be received.
|
| + MCSMessage message1(BuildDownstreamMessage(
|
| + kSender, kExtensionAppId, std::string() /* subtype */, expected_data,
|
| + std::string() /* raw_data */));
|
| + EXPECT_TRUE(message1.IsValid());
|
| + ReceiveMessageFromMCS(message1);
|
| +
|
| + EXPECT_EQ(MESSAGE_RECEIVED, last_event());
|
| + EXPECT_EQ(kExtensionAppId, last_app_id());
|
| + EXPECT_EQ(expected_data.size(), last_message().data.size());
|
| + EXPECT_EQ(expected_data, last_message().data);
|
| + EXPECT_EQ(kSender, last_message().sender_id);
|
| +
|
| + // The only way to check that no messages were sent is to check that the tag
|
| + // is still the default value.
|
| + EXPECT_EQ(MCSProtoTag::kNumProtoTypes, mcs_client()->last_message_tag());
|
| +}
|
| +
|
| TEST_F(GCMClientInstanceIDTest, DispatchDownstreamMessageWithSubtype) {
|
| + // Initialize a field trial for sending message receipts and set the messages
|
| + // to send to 2 = ALL.
|
| + InitializeFieldTrials(2);
|
| +
|
| AddInstanceID(kSubtypeAppId, kInstanceID);
|
| GetToken(kSubtypeAppId, kSender, kScope);
|
| ASSERT_NO_FATAL_FAILURE(CompleteRegistration("token1"));
|
| @@ -1850,6 +2028,24 @@ TEST_F(GCMClientInstanceIDTest, DispatchDownstreamMessageWithSubtype) {
|
|
|
| EXPECT_NE(MESSAGE_RECEIVED, last_event());
|
|
|
| + // Check that the last message sent was a message receipt for a failed message
|
| + // and that it had the values expected.
|
| + mcs_proto::DataMessageStanza stanza =
|
| + mcs_client()->last_data_message_stanza();
|
| + EXPECT_EQ(kSubtypeAppId, stanza.category());
|
| + const auto& app_data = stanza.app_data();
|
| + ASSERT_EQ(3, app_data.size());
|
| + for (const auto& pair : app_data) {
|
| + if (pair.key() == "message_id")
|
| + EXPECT_EQ("", pair.value());
|
| + else if (pair.key() == "status")
|
| + EXPECT_EQ("2", pair.value());
|
| + else if (pair.key() == "message_type")
|
| + EXPECT_EQ("message_receipt", pair.value());
|
| + else
|
| + FAIL() << "Unexpected key: " << pair.key();
|
| + }
|
| +
|
| reset_last_event();
|
|
|
| // Message for kSender will be received.
|
|
|