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. |