blob: 1ca15685f416729ac325c1850352f41f7ff794d3 [file] [log] [blame]
// 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