Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Unified Diff: third_party/cacheinvalidation/src/google/cacheinvalidation/impl/protocol-handler_test.cc

Issue 1162033004: Pull cacheinvalidations code directory into chromium repo. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/cacheinvalidation/src/google/cacheinvalidation/impl/protocol-handler_test.cc
diff --git a/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/protocol-handler_test.cc b/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/protocol-handler_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1ca15685f416729ac325c1850352f41f7ff794d3
--- /dev/null
+++ b/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/protocol-handler_test.cc
@@ -0,0 +1,674 @@
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Unit tests for the ProtocolHandler class.
+
+#include "google/cacheinvalidation/types.pb.h"
+#include "google/cacheinvalidation/include/types.h"
+#include "google/cacheinvalidation/deps/gmock.h"
+#include "google/cacheinvalidation/deps/googletest.h"
+#include "google/cacheinvalidation/deps/string_util.h"
+#include "google/cacheinvalidation/impl/basic-system-resources.h"
+#include "google/cacheinvalidation/impl/constants.h"
+#include "google/cacheinvalidation/impl/invalidation-client-impl.h"
+#include "google/cacheinvalidation/impl/protocol-handler.h"
+#include "google/cacheinvalidation/impl/statistics.h"
+#include "google/cacheinvalidation/impl/throttle.h"
+#include "google/cacheinvalidation/impl/ticl-message-validator.h"
+#include "google/cacheinvalidation/test/deterministic-scheduler.h"
+#include "google/cacheinvalidation/test/test-logger.h"
+#include "google/cacheinvalidation/test/test-utils.h"
+
+namespace invalidation {
+
+using ::ipc::invalidation::ClientType_Type_TEST;
+using ::ipc::invalidation::ObjectSource_Type_TEST;
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::ByRef;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::EqualsProto;
+using ::testing::Eq;
+using ::testing::Matcher;
+using ::testing::Property;
+using ::testing::Return;
+using ::testing::ReturnPointee;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+using ::testing::proto::WhenDeserializedAs;
+
+/* Returns whether two headers are equal. */
+bool HeaderEqual(const ServerMessageHeader& expected,
+ const ServerMessageHeader& actual) {
+ // If the token is different or if one of the registration summaries is NULL
+ // and the other is non-NULL, return false.
+ if (((expected.registration_summary() != NULL) !=
+ (actual.registration_summary() != NULL)) ||
+ (expected.token() != actual.token())) {
+ return false;
+ }
+
+ // The tokens are the same and registration summaries are either both
+ // null or non-null.
+ return (expected.registration_summary() == NULL) ||
+ ((expected.registration_summary()->num_registrations() ==
+ actual.registration_summary()->num_registrations()) &&
+ (expected.registration_summary()->registration_digest() ==
+ actual.registration_summary()->registration_digest()));
+}
+
+// A mock of the ProtocolListener interface.
+class MockProtocolListener : public ProtocolListener {
+ public:
+ MOCK_METHOD0(HandleMessageSent, void());
+
+ MOCK_METHOD1(HandleNetworkStatusChange, void(bool)); // NOLINT
+
+ MOCK_METHOD1(GetRegistrationSummary, void(RegistrationSummary*)); // NOLINT
+
+ MOCK_METHOD0(GetClientToken, string());
+};
+
+// Tests the basic functionality of the protocol handler.
+class ProtocolHandlerTest : public UnitTestBase {
+ public:
+ virtual ~ProtocolHandlerTest() {}
+
+ // Performs setup for protocol handler unit tests, e.g. creating resource
+ // components and setting up common expectations for certain mock objects.
+ virtual void SetUp() {
+ // Use a strict mock scheduler for the listener, since it shouldn't be used
+ // at all by the protocol handler.
+ UnitTestBase::SetUp();
+ InitListenerExpectations();
+ validator.reset(new TiclMessageValidator(logger)); // Create msg validator
+
+ // Create the protocol handler object.
+ random.reset(new Random(InvalidationClientUtil::GetCurrentTimeMs(
+ resources.get()->internal_scheduler())));
+ smearer.reset(new Smearer(random.get(), kDefaultSmearPercent));
+ protocol_handler.reset(
+ new ProtocolHandler(
+ config, resources.get(), smearer.get(), statistics.get(),
+ ClientType_Type_TEST, "unit-test", &listener, validator.get()));
+ batching_task.reset(
+ new BatchingTask(protocol_handler.get(), smearer.get(),
+ TimeDelta::FromMilliseconds(config.batching_delay_ms())));
+ }
+
+ // Configuration for the protocol handler (uses defaults).
+ ProtocolHandlerConfigP config;
+
+ // The protocol handler being tested. Created fresh for each test function.
+ scoped_ptr<ProtocolHandler> protocol_handler;
+
+ // A mock protocol listener. We make this strict in order to have tight
+ // control over the interactions between this and the protocol handler.
+ // SetUp() installs expectations to allow GetClientToken() and
+ // GetRegistrationSummary() to be called any time and to give them
+ // reasonable behavior.
+ StrictMock<MockProtocolListener> listener;
+
+ // Ticl message validator. We do not mock this, since the correctness of the
+ // protocol handler depends on it.
+ scoped_ptr<TiclMessageValidator> validator;
+
+ // Token and registration summary for the mock listener to return when
+ // the protocol handler requests them.
+ string token;
+ RegistrationSummary summary;
+
+ // A smearer to randomize delays.
+ scoped_ptr<Smearer> smearer;
+
+ // A random number generator.
+ scoped_ptr<Random> random;
+
+ // Batching task for the protocol handler.
+ scoped_ptr<BatchingTask> batching_task;
+
+ void AddExpectationForHandleMessageSent() {
+ EXPECT_CALL(listener, HandleMessageSent());
+ }
+
+ /*
+ * Processes a |message| using the protocol handler, initializing
+ * |parsed_message| with the result.
+ *
+ * Returns whether the message could be parsed.
+ */
+ bool ProcessMessage(ServerToClientMessage message,
+ ParsedMessage* parsed_message) {
+ string serialized;
+ message.SerializeToString(&serialized);
+ bool accepted = protocol_handler->HandleIncomingMessage(
+ serialized, parsed_message);
+ return accepted;
+ }
+
+ private:
+ void InitListenerExpectations() {
+ // When the handler asks the listener for the client token, return whatever
+ // |token| currently is.
+ EXPECT_CALL(listener, GetClientToken())
+ .WillRepeatedly(ReturnPointee(&token));
+
+ // If the handler asks the listener for a registration summary, respond by
+ // supplying a fake summary.
+ InitZeroRegistrationSummary(&summary);
+ EXPECT_CALL(listener, GetRegistrationSummary(_))
+ .WillRepeatedly(SetArgPointee<0>(summary));
+ }
+};
+
+// Asks the protocol handler to send an initialize message. Waits for the
+// batching delay to pass. Checks that appropriate calls are made on the
+// listener and that a proper message is sent on the network.
+TEST_F(ProtocolHandlerTest, SendInitializeOnly) {
+ ApplicationClientIdP app_client_id;
+ app_client_id.set_client_name("unit-test-client-id");
+ app_client_id.set_client_type(ClientType_Type_TEST);
+
+ // Client's token is initially empty. Give it an arbitrary nonce.
+ token = "";
+ string nonce = "unit-test-nonce";
+
+ // SendInitializeMessage checks that it's running on the work queue thread, so
+ // we need to schedule the call.
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendInitializeMessage,
+ app_client_id, nonce, batching_task.get(), "Startup"));
+
+ AddExpectationForHandleMessageSent();
+ ClientToServerMessage expected_message;
+
+ // Build the header.
+ ClientHeader* header = expected_message.mutable_header();
+ ProtoHelpers::InitProtocolVersion(header->mutable_protocol_version());
+ header->mutable_registration_summary()->CopyFrom(summary);
+ header->set_max_known_server_time_ms(0);
+ header->set_message_id("1");
+
+ // Note: because the batching task is smeared, we don't know what the client's
+ // timestamp will be. We omit it from this proto and do a partial match in
+ // the EXPECT_CALL but also save the proto and check later that it doesn't
+ // contain anything we don't expect.
+
+ // Create the expected initialize message.
+ InitializeMessage* initialize_message =
+ expected_message.mutable_initialize_message();
+ initialize_message->set_client_type(ClientType_Type_TEST);
+ initialize_message->set_nonce(nonce);
+ initialize_message->mutable_application_client_id()->CopyFrom(app_client_id);
+ initialize_message->set_digest_serialization_type(
+ InitializeMessage_DigestSerializationType_BYTE_BASED);
+
+ string actual_serialized;
+ EXPECT_CALL(
+ *network,
+ SendMessage(WhenDeserializedAs<ClientToServerMessage>(
+ // Check that the deserialized message has the initialize message and
+ // header fields we expect.
+ AllOf(Property(&ClientToServerMessage::initialize_message,
+ EqualsProto(*initialize_message)),
+ Property(&ClientToServerMessage::header,
+ ClientHeaderMatches(header))))))
+ .WillOnce(SaveArg<0>(&actual_serialized));
+
+ // The actual message won't be sent until after the batching delay, which is
+ // smeared, so double it to be sure enough time will have passed.
+ TimeDelta wait_time = GetMaxBatchingDelay(config);
+ internal_scheduler->PassTime(wait_time);
+
+ // By now we expect the message to have been sent, so we'll deserialize it
+ // and check that it doesn't have anything we don't expect.
+ ClientToServerMessage actual_message;
+ actual_message.ParseFromString(actual_serialized);
+ ASSERT_FALSE(actual_message.has_info_message());
+ ASSERT_FALSE(actual_message.has_invalidation_ack_message());
+ ASSERT_FALSE(actual_message.has_registration_message());
+ ASSERT_FALSE(actual_message.has_registration_sync_message());
+ ASSERT_GE(actual_message.header().client_time_ms(),
+ InvalidationClientUtil::GetTimeInMillis(start_time));
+ ASSERT_LE(actual_message.header().client_time_ms(),
+ InvalidationClientUtil::GetTimeInMillis(start_time + wait_time));
+}
+
+// Tests the receipt of a token control message like what we'd expect in
+// response to an initialize message. Check that appropriate calls are made on
+// the protocol listener.
+TEST_F(ProtocolHandlerTest, ReceiveTokenControlOnly) {
+ ServerToClientMessage message;
+ ServerHeader* header = message.mutable_header();
+ string nonce = "fake nonce";
+ InitServerHeader(nonce, header);
+
+ string new_token = "new token";
+ message.mutable_token_control_message()->set_new_token(new_token);
+
+ ServerMessageHeader expected_header;
+ expected_header.InitFrom(&nonce, &header->registration_summary());
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_TRUE(HeaderEqual(expected_header, parsed_message.header));
+ ASSERT_TRUE(parsed_message.token_control_message != NULL);
+}
+
+// Test that the protocol handler correctly buffers multiple message types.
+// Tell it to send registrations, then unregistrations (with some overlap in the
+// sets of objects). Then send some invalidation acks and finally a
+// registration subtree. Wait for the batching interval to pass, and then check
+// that the message sent out contains everything we expect.
+TEST_F(ProtocolHandlerTest, SendMultipleMessageTypes) {
+ // Concoct some performance counters and config parameters, and ask to send
+ // an info message with them.
+ vector<pair<string, int> > perf_counters;
+ perf_counters.push_back(make_pair("x", 3));
+ perf_counters.push_back(make_pair("y", 81));
+ ClientConfigP client_config;
+ InvalidationClientImpl::InitConfig(&client_config);
+
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendInfoMessage,
+ perf_counters, &client_config, true, batching_task.get()));
+
+ // Synthesize a few test object ids.
+ vector<ObjectIdP> oids;
+ InitTestObjectIds(3, &oids);
+
+ // Register for the first two.
+ vector<ObjectIdP> oid_vec;
+ oid_vec.push_back(oids[0]);
+ oid_vec.push_back(oids[1]);
+
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendRegistrations,
+ oid_vec, RegistrationP_OpType_REGISTER, batching_task.get()));
+
+ // Then unregister for the second and third. This overrides the registration
+ // on oids[1].
+ oid_vec.clear();
+ oid_vec.push_back(oids[1]);
+ oid_vec.push_back(oids[2]);
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendRegistrations,
+ oid_vec, RegistrationP_OpType_UNREGISTER, batching_task.get()));
+
+ // Send a couple of invalidations.
+ vector<InvalidationP> invalidations;
+ MakeInvalidationsFromObjectIds(oids, &invalidations);
+ invalidations.pop_back();
+ for (size_t i = 0; i < invalidations.size(); ++i) {
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendInvalidationAck,
+ invalidations[i], batching_task.get()));
+ }
+
+ // Send a simple registration subtree.
+ RegistrationSubtree subtree;
+ subtree.add_registered_object()->CopyFrom(oids[0]);
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendRegistrationSyncSubtree,
+ subtree, batching_task.get()));
+
+ AddExpectationForHandleMessageSent();
+
+ token = "test token";
+
+ // The message it sends should contain all of the expected information:
+ ClientToServerMessage expected_message;
+
+ // Header.
+ ClientHeader* header = expected_message.mutable_header();
+ ProtoHelpers::InitProtocolVersion(header->mutable_protocol_version());
+ header->mutable_registration_summary()->CopyFrom(summary);
+ header->set_client_token(token);
+ header->set_max_known_server_time_ms(0);
+ header->set_message_id("1");
+
+ // Note: because the batching task is smeared, we don't know what the client's
+ // timestamp will be. We omit it from this proto and do a partial match in
+ // the EXPECT_CALL but also save the proto and check later that it doesn't
+ // contain anything we don't expect.
+
+ // Registrations.
+ RegistrationMessage* reg_message =
+ expected_message.mutable_registration_message();
+ RegistrationP* registration;
+ registration = reg_message->add_registration();
+ registration->mutable_object_id()->CopyFrom(oids[0]);
+ registration->set_op_type(RegistrationP_OpType_REGISTER);
+
+ registration = reg_message->add_registration();
+ registration->mutable_object_id()->CopyFrom(oids[1]);
+ registration->set_op_type(RegistrationP_OpType_UNREGISTER);
+
+ registration = reg_message->add_registration();
+ registration->mutable_object_id()->CopyFrom(oids[2]);
+ registration->set_op_type(RegistrationP_OpType_UNREGISTER);
+
+ // Registration sync message.
+ expected_message.mutable_registration_sync_message()->add_subtree()
+ ->CopyFrom(subtree);
+
+ // Invalidation acks.
+ InvalidationMessage* invalidation_message =
+ expected_message.mutable_invalidation_ack_message();
+ InitInvalidationMessage(invalidations, invalidation_message);
+
+ // Info message.
+ InfoMessage* info_message = expected_message.mutable_info_message();
+ ProtoHelpers::InitClientVersion("unit-test", "unit-test",
+ info_message->mutable_client_version());
+ info_message->set_server_registration_summary_requested(true);
+ info_message->mutable_client_config()->CopyFrom(client_config);
+ PropertyRecord* prop_rec;
+ for (uint32 i = 0; i < perf_counters.size(); ++i) {
+ prop_rec = info_message->add_performance_counter();
+ prop_rec->set_name(perf_counters[i].first);
+ prop_rec->set_value(perf_counters[i].second);
+ }
+
+ string actual_serialized;
+ EXPECT_CALL(
+ *network,
+ SendMessage(
+ WhenDeserializedAs<ClientToServerMessage>(
+ // Check that the deserialized message has the invalidation acks,
+ // registrations, info message, and header fields we expect.
+ AllOf(Property(&ClientToServerMessage::invalidation_ack_message,
+ EqualsProto(*invalidation_message)),
+ Property(&ClientToServerMessage::registration_message,
+ EqualsProto(*reg_message)),
+ Property(&ClientToServerMessage::info_message,
+ EqualsProto(*info_message)),
+ Property(&ClientToServerMessage::header,
+ ClientHeaderMatches(header))))))
+ .WillOnce(SaveArg<0>(&actual_serialized));
+
+ TimeDelta wait_time = GetMaxBatchingDelay(config);
+ internal_scheduler->PassTime(wait_time);
+
+ ClientToServerMessage actual_message;
+ actual_message.ParseFromString(actual_serialized);
+
+ ASSERT_FALSE(actual_message.has_initialize_message());
+ ASSERT_GE(actual_message.header().client_time_ms(),
+ InvalidationClientUtil::GetTimeInMillis(start_time));
+ ASSERT_LE(actual_message.header().client_time_ms(),
+ InvalidationClientUtil::GetTimeInMillis(start_time + wait_time));
+}
+
+// Check that if the protocol handler receives a message with several sub-
+// messages set, it makes all the appropriate calls on the listener.
+TEST_F(ProtocolHandlerTest, IncomingCompositeMessage) {
+ // Build up a message with a number of sub-messages in it:
+ ServerToClientMessage message;
+
+ // First the header.
+ token = "test token";
+ InitServerHeader(token, message.mutable_header());
+
+ // Fabricate a few object ids for use in invalidations and registration
+ // statuses.
+ vector<ObjectIdP> object_ids;
+ InitTestObjectIds(3, &object_ids);
+
+ // Add invalidations.
+ vector<InvalidationP> invalidations;
+ MakeInvalidationsFromObjectIds(object_ids, &invalidations);
+ for (int i = 0; i < 3; ++i) {
+ message.mutable_invalidation_message()->add_invalidation()->CopyFrom(
+ invalidations[i]);
+ }
+
+ // Add registration statuses.
+ vector<RegistrationStatus> registration_statuses;
+ MakeRegistrationStatusesFromObjectIds(object_ids, true, true,
+ &registration_statuses);
+ for (int i = 0; i < 3; ++i) {
+ message.mutable_registration_status_message()
+ ->add_registration_status()->CopyFrom(registration_statuses[i]);
+ }
+
+ // Add a registration sync request message.
+ message.mutable_registration_sync_request_message();
+
+ // Add an info request message.
+ message.mutable_info_request_message()->add_info_type(
+ InfoRequestMessage_InfoType_GET_PERFORMANCE_COUNTERS);
+
+ // The header we expect the listener to be called with.
+ ServerMessageHeader expected_header;
+ expected_header.InitFrom(&token, &summary);
+
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_TRUE(HeaderEqual(expected_header, parsed_message.header));
+ ASSERT_TRUE(parsed_message.invalidation_message != NULL);
+ ASSERT_TRUE(parsed_message.registration_status_message != NULL);
+ ASSERT_TRUE(parsed_message.registration_sync_request_message != NULL);
+ ASSERT_TRUE(parsed_message.info_request_message != NULL);
+}
+
+// Test that the protocol handler drops an invalid message.
+TEST_F(ProtocolHandlerTest, InvalidInboundMessage) {
+ // Make an invalid message (omit protocol version from header).
+ ServerToClientMessage message;
+ string token = "test token";
+ ServerHeader* header = message.mutable_header();
+ InitServerHeader(token, header);
+ header->clear_protocol_version();
+
+ // Add an info request message to check that it doesn't get processed.
+ message.mutable_info_request_message()->add_info_type(
+ InfoRequestMessage_InfoType_GET_PERFORMANCE_COUNTERS);
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_EQ(1, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_INCOMING_MESSAGE_FAILURE));
+}
+
+// Test that the protocol handler drops a message whose major version doesn't
+// match what it understands.
+TEST_F(ProtocolHandlerTest, MajorVersionMismatch) {
+ // Make a message with a different protocol major version.
+ ServerToClientMessage message;
+ token = "test token";
+ ServerHeader* header = message.mutable_header();
+ InitServerHeader(token, header);
+ header->mutable_protocol_version()->mutable_version()->set_major_version(1);
+
+ // Add an info request message to check that it doesn't get processed.
+ message.mutable_info_request_message()->add_info_type(
+ InfoRequestMessage_InfoType_GET_PERFORMANCE_COUNTERS);
+
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_EQ(1, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_PROTOCOL_VERSION_FAILURE));
+}
+
+// Test that the protocol handler doesn't drop a message whose minor version
+// doesn't match what it understands.
+TEST_F(ProtocolHandlerTest, MinorVersionMismatch) {
+ // Make a message with a different protocol minor version.
+ ServerToClientMessage message;
+ token = "test token";
+ ServerHeader* header = message.mutable_header();
+ InitServerHeader(token, header);
+ header->mutable_protocol_version()->mutable_version()->set_minor_version(4);
+
+ ServerMessageHeader expected_header;
+ expected_header.InitFrom(&token, &summary);
+
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_TRUE(HeaderEqual(expected_header, parsed_message.header));
+ ASSERT_EQ(0, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_PROTOCOL_VERSION_FAILURE));
+}
+
+// Test that the protocol handler honors a config message (even if the server
+// token doesn't match) and does not call any listener methods.
+TEST_F(ProtocolHandlerTest, ConfigMessage) {
+ // Fabricate a config message.
+ ServerToClientMessage message;
+ token = "test token";
+ InitServerHeader(token, message.mutable_header());
+ token = "token-that-should-mismatch";
+
+ int next_message_delay_ms = 2000 * 1000;
+ message.mutable_config_change_message()->set_next_message_delay_ms(
+ next_message_delay_ms);
+
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+
+ // Check that the protocol handler recorded receiving the config change
+ // message, and that it has updated the next time it will send a message.
+ ASSERT_EQ(1, statistics->GetReceivedMessageCounterForTest(
+ Statistics::ReceivedMessageType_CONFIG_CHANGE));
+ ASSERT_EQ(
+ InvalidationClientUtil::GetTimeInMillis(
+ start_time + TimeDelta::FromMilliseconds(next_message_delay_ms)),
+ protocol_handler->GetNextMessageSendTimeMsForTest());
+
+ // Request to send an info message, and check that it doesn't get sent.
+ vector<pair<string, int> > empty_vector;
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(), &ProtocolHandler::SendInfoMessage,
+ empty_vector, NULL, false, batching_task.get()));
+
+ // Keep simulating passage of time until just before the quiet period ends.
+ // Nothing should be sent. (The mock network will catch any attempts to send
+ // and fail the test.)
+ internal_scheduler->PassTime(
+ TimeDelta::FromMilliseconds(next_message_delay_ms - 1));
+}
+
+// Test that the protocol handler properly delivers an error message to the
+// listener.
+TEST_F(ProtocolHandlerTest, ErrorMessage) {
+ // Fabricate an error message.
+ ServerToClientMessage message;
+ token = "test token";
+ InitServerHeader(token, message.mutable_header());
+
+ // Add an error message.
+ ErrorMessage::Code error_code = ErrorMessage_Code_AUTH_FAILURE;
+ string description = "invalid auth token";
+ InitErrorMessage(error_code, description, message.mutable_error_message());
+ ServerMessageHeader expected_header;
+ expected_header.InitFrom(&token, &summary);
+
+ // Deliver the message.
+ ParsedMessage parsed_message;
+ ProcessMessage(message, &parsed_message);
+ ASSERT_TRUE(HeaderEqual(expected_header, parsed_message.header));
+ ASSERT_TRUE(parsed_message.error_message != NULL);
+}
+
+// Tests that the protocol handler accepts a message from the server if the
+// token doesn't match the client's (the caller is responsible for checking
+// the token).
+TEST_F(ProtocolHandlerTest, TokenMismatch) {
+ // Create the server message with one token.
+ token = "test token";
+ ServerToClientMessage message;
+ InitServerHeader(token, message.mutable_header());
+
+ // Give the client a different token.
+ token = "token-that-should-mismatch";
+
+ // Deliver the message.
+ ParsedMessage parsed_message;
+ bool accepted = ProcessMessage(message, &parsed_message);
+ ASSERT_TRUE(accepted);
+
+ ASSERT_EQ(0, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_TOKEN_MISMATCH));
+}
+
+// Tests that the protocol handler won't send out a non-initialize message if
+// the client has no token.
+TEST_F(ProtocolHandlerTest, TokenMissing) {
+ token = "";
+ vector<pair<string, int> > empty_vector;
+
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(),
+ &ProtocolHandler::SendInfoMessage, empty_vector, NULL, true,
+ batching_task.get()));
+
+ internal_scheduler->PassTime(GetMaxBatchingDelay(config));
+
+ ASSERT_EQ(1, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_TOKEN_MISSING_FAILURE));
+}
+
+// Tests that the protocol handler won't send out a message that fails
+// validation (in this case, an invalidation ack with a missing version).
+TEST_F(ProtocolHandlerTest, InvalidOutboundMessage) {
+ token = "test token";
+
+ vector<ObjectIdP> object_ids;
+ InitTestObjectIds(1, &object_ids);
+ vector<InvalidationP> invalidations;
+ MakeInvalidationsFromObjectIds(object_ids, &invalidations);
+ invalidations[0].clear_version();
+
+ internal_scheduler->Schedule(
+ Scheduler::NoDelay(),
+ NewPermanentCallback(
+ protocol_handler.get(),
+ &ProtocolHandler::SendInvalidationAck,
+ invalidations[0],
+ batching_task.get()));
+
+ internal_scheduler->PassTime(GetMaxBatchingDelay(config));
+
+ ASSERT_EQ(1, statistics->GetClientErrorCounterForTest(
+ Statistics::ClientErrorType_OUTGOING_MESSAGE_FAILURE));
+}
+
+// Tests that the protocol handler drops an unparseable message.
+TEST_F(ProtocolHandlerTest, UnparseableInboundMessage) {
+ // Make an unparseable message.
+ string serialized = "this can't be a valid protocol buffer!";
+ ParsedMessage parsed_message;
+ bool accepted = protocol_handler->HandleIncomingMessage(serialized,
+ &parsed_message);
+ ASSERT_FALSE(accepted);
+}
+
+} // namespace invalidation

Powered by Google App Engine
This is Rietveld 408576698