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

Unified Diff: third_party/cacheinvalidation/src/google/cacheinvalidation/impl/invalidation-client-impl_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/invalidation-client-impl_test.cc
diff --git a/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/invalidation-client-impl_test.cc b/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/invalidation-client-impl_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ab72ef2b0a13dd81a7c20a345d14440f34ddfb81
--- /dev/null
+++ b/third_party/cacheinvalidation/src/google/cacheinvalidation/impl/invalidation-client-impl_test.cc
@@ -0,0 +1,504 @@
+// 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 InvalidationClientImpl class.
+
+#include <vector>
+
+#include "google/cacheinvalidation/client_test_internal.pb.h"
+#include "google/cacheinvalidation/types.pb.h"
+#include "google/cacheinvalidation/include/invalidation-listener.h"
+#include "google/cacheinvalidation/include/types.h"
+#include "google/cacheinvalidation/deps/gmock.h"
+#include "google/cacheinvalidation/deps/googletest.h"
+#include "google/cacheinvalidation/deps/random.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/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::RegistrationManagerStateP;
+using ::ipc::invalidation::ObjectSource_Type_TEST;
+using ::ipc::invalidation::StatusP_Code_PERMANENT_FAILURE;
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::DeleteArg;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::EqualsProto;
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::InvokeArgument;
+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;
+
+// Creates an action SaveArgToVector<k>(vector*) that saves the kth argument in
+// |vec|.
+ACTION_TEMPLATE(
+ SaveArgToVector,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(vec)) {
+ vec->push_back(std::tr1::get<k>(args));
+}
+
+// Given the ReadCallback of Storage::ReadKey as argument 1, invokes it with a
+// permanent failure status code.
+ACTION(InvokeReadCallbackFailure) {
+ arg1->Run(pair<Status, string>(Status(Status::PERMANENT_FAILURE, ""), ""));
+ delete arg1;
+}
+
+// Given the WriteCallback of Storage::WriteKey as argument 2, invokes it with
+// a success status code.
+ACTION(InvokeWriteCallbackSuccess) {
+ arg2->Run(Status(Status::SUCCESS, ""));
+ delete arg2;
+}
+
+// Tests the basic functionality of the invalidation client.
+class InvalidationClientImplTest : public UnitTestBase {
+ public:
+ virtual ~InvalidationClientImplTest() {}
+
+ // Performs setup for protocol handler unit tests, e.g. creating resource
+ // components and setting up common expectations for certain mock objects.
+ virtual void SetUp() {
+ UnitTestBase::SetUp();
+ InitCommonExpectations(); // Set up expectations for common mock operations
+
+
+ // Clear throttle limits so that it does not interfere with any test.
+ InvalidationClientImpl::InitConfig(&config);
+ config.set_smear_percent(kDefaultSmearPercent);
+ config.mutable_protocol_handler_config()->clear_rate_limit();
+
+ // Set up the listener scheduler to run any runnable that it receives.
+ EXPECT_CALL(*listener_scheduler, Schedule(_, _))
+ .WillRepeatedly(InvokeAndDeleteClosure<1>());
+
+ // Create the actual client.
+ Random* random = new Random(InvalidationClientUtil::GetCurrentTimeMs(
+ resources->internal_scheduler()));
+ client.reset(new InvalidationClientImpl(
+ resources.get(), random, ClientType_Type_TEST, "clientName", config,
+ "InvClientTest", &listener));
+ }
+
+ // Starts the Ticl and ensures that the initialize message is sent. In
+ // response, gives a tokencontrol message to the protocol handler and makes
+ // sure that ready is called. client_messages is the list of messages expected
+ // from the client. The 0th message corresponds to the initialization message
+ // sent out by the client.
+ void StartClient() {
+ // Start the client.
+ client.get()->Start();
+
+ // Let the message be sent out.
+ internal_scheduler->PassTime(
+ GetMaxBatchingDelay(config.protocol_handler_config()));
+
+ // Check that the message contains an initializeMessage.
+ ClientToServerMessage client_message;
+ client_message.ParseFromString(outgoing_messages[0]);
+ ASSERT_TRUE(client_message.has_initialize_message());
+ string nonce = client_message.initialize_message().nonce();
+
+ // Create the token control message and hand it to the protocol handler.
+ ServerToClientMessage sc_message;
+ InitServerHeader(nonce, sc_message.mutable_header());
+ string new_token = "new token";
+ sc_message.mutable_token_control_message()->set_new_token(new_token);
+ ProcessIncomingMessage(sc_message, MessageHandlingDelay());
+ }
+
+ // Sets the expectations so that the Ticl is ready to be started such that
+ // |num_outgoing_messages| are expected to be sent by the ticl. These messages
+ // will be saved in |outgoing_messages|.
+ void SetExpectationsForTiclStart(int num_outgoing_msgs) {
+ // Set up expectations for number of messages expected on the network.
+ EXPECT_CALL(*network, SendMessage(_))
+ .Times(num_outgoing_msgs)
+ .WillRepeatedly(SaveArgToVector<0>(&outgoing_messages));
+
+ // Expect the storage to perform a read key that we will fail.
+ EXPECT_CALL(*storage, ReadKey(_, _))
+ .WillOnce(InvokeReadCallbackFailure());
+
+ // Expect the listener to indicate that it is ready and let it reissue
+ // registrations.
+ EXPECT_CALL(listener, Ready(Eq(client.get())));
+ EXPECT_CALL(listener, ReissueRegistrations(Eq(client.get()), _, _));
+
+ // Expect the storage layer to receive the write of the session token.
+ EXPECT_CALL(*storage, WriteKey(_, _, _))
+ .WillOnce(InvokeWriteCallbackSuccess());
+ }
+
+ //
+ // Test state maintained for every test.
+ //
+
+ // Messages sent by the Ticl.
+ vector<string> outgoing_messages;
+
+ // Configuration for the protocol handler (uses defaults).
+ ClientConfigP config;
+
+ // The client being tested. Created fresh for each test function.
+ scoped_ptr<InvalidationClientImpl> client;
+
+ // A mock invalidation listener.
+ StrictMock<MockInvalidationListener> listener;
+};
+
+// Starts the ticl and checks that appropriate calls are made on the listener
+// and that a proper message is sent on the network.
+TEST_F(InvalidationClientImplTest, Start) {
+ SetExpectationsForTiclStart(1);
+ StartClient();
+}
+
+// Tests that GenerateNonce generates a unique nonce on every call.
+TEST_F(InvalidationClientImplTest, GenerateNonce) {
+ // Create a random number generated seeded with the current time.
+ scoped_ptr<Random> random;
+ random.reset(new Random(InvalidationClientUtil::GetCurrentTimeMs(
+ resources->internal_scheduler())));
+
+ // Generate two nonces and make sure they are distinct. (The chances
+ // of a collision should be vanishingly small since our correctness
+ // relies upon no collisions.)
+ string nonce1 = InvalidationClientCore::GenerateNonce(random.get());
+ string nonce2 = InvalidationClientCore::GenerateNonce(random.get());
+ ASSERT_NE(nonce1, nonce2);
+}
+
+// Starts the Ticl, registers for a few objects, gets success and ensures that
+// the right listener methods are invoked.
+TEST_F(InvalidationClientImplTest, Register) {
+ SetExpectationsForTiclStart(2);
+
+ // Set some expectations for registration status messages.
+ vector<ObjectId> saved_oids;
+ EXPECT_CALL(listener,
+ InformRegistrationStatus(Eq(client.get()), _,
+ InvalidationListener::REGISTERED))
+ .Times(3)
+ .WillRepeatedly(SaveArgToVector<1>(&saved_oids));
+
+ // Start the Ticl.
+ StartClient();
+
+ // Synthesize a few test object ids.
+ int num_objects = 3;
+ vector<ObjectIdP> oid_protos;
+ vector<ObjectId> oids;
+ InitTestObjectIds(num_objects, &oid_protos);
+ ConvertFromObjectIdProtos(oid_protos, &oids);
+
+ // Register
+ client.get()->Register(oids);
+
+ // Let the message be sent out.
+ internal_scheduler->PassTime(
+ GetMaxBatchingDelay(config.protocol_handler_config()));
+
+ // Give a registration status message to the protocol handler and wait for
+ // the listener calls.
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+ vector<RegistrationStatus> registration_statuses;
+ MakeRegistrationStatusesFromObjectIds(oid_protos, true, true,
+ &registration_statuses);
+ for (int i = 0; i < num_objects; ++i) {
+ message.mutable_registration_status_message()
+ ->add_registration_status()->CopyFrom(registration_statuses[i]);
+ }
+
+ // Give this message to the protocol handler.
+ ProcessIncomingMessage(message, EndOfTestWaitTime());
+
+ // Check the object ids.
+ ASSERT_TRUE(CompareVectorsAsSets(saved_oids, oids));
+
+ // Check the registration message.
+ ClientToServerMessage client_msg;
+ client_msg.ParseFromString(outgoing_messages[1]);
+ ASSERT_TRUE(client_msg.has_registration_message());
+ ASSERT_FALSE(client_msg.has_info_message());
+ ASSERT_FALSE(client_msg.has_registration_sync_message());
+
+ RegistrationMessage expected_msg;
+ InitRegistrationMessage(oid_protos, true, &expected_msg);
+ const RegistrationMessage& actual_msg = client_msg.registration_message();
+ ASSERT_TRUE(CompareMessages(expected_msg, actual_msg));
+}
+
+// Tests that given invalidations from the server, the right listener methods
+// are invoked. Ack the invalidations and make sure that the ack message is sent
+// out. Include a payload in one invalidation and make sure the client does not
+// include it in the ack.
+TEST_F(InvalidationClientImplTest, Invalidations) {
+ // Set some expectations for starting the client.
+ SetExpectationsForTiclStart(2);
+
+ // Synthesize a few test object ids.
+ int num_objects = 3;
+ vector<ObjectIdP> oid_protos;
+ vector<ObjectId> oids;
+ InitTestObjectIds(num_objects, &oid_protos);
+ ConvertFromObjectIdProtos(oid_protos, &oids);
+
+ // Set up listener invalidation calls.
+ vector<InvalidationP> invalidations;
+ vector<Invalidation> expected_invs;
+ MakeInvalidationsFromObjectIds(oid_protos, &invalidations);
+ // Put a payload in one of the invalidations.
+ invalidations[0].set_payload("this is a payload");
+ ConvertFromInvalidationProtos(invalidations, &expected_invs);
+
+ // Set up expectations for the acks.
+ vector<Invalidation> saved_invs;
+ vector<AckHandle> ack_handles;
+
+ EXPECT_CALL(listener, Invalidate(Eq(client.get()), _, _))
+ .Times(3)
+ .WillRepeatedly(DoAll(SaveArgToVector<1>(&saved_invs),
+ SaveArgToVector<2>(&ack_handles)));
+
+ // Start the Ticl.
+ StartClient();
+
+ // Give this message to the protocol handler.
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+ InitInvalidationMessage(invalidations,
+ message.mutable_invalidation_message());
+
+ // Process the incoming invalidation message.
+ ProcessIncomingMessage(message, MessageHandlingDelay());
+
+ // Check the invalidations.
+ ASSERT_TRUE(CompareVectorsAsSets(expected_invs, saved_invs));
+
+ // Ack the invalidations now and wait for them to be sent out.
+ for (int i = 0; i < num_objects; i++) {
+ client.get()->Acknowledge(ack_handles[i]);
+ }
+ internal_scheduler->PassTime(
+ GetMaxBatchingDelay(config.protocol_handler_config()));
+
+ // Check that the ack message is as expected.
+ ClientToServerMessage client_msg;
+ client_msg.ParseFromString(outgoing_messages[1]);
+ ASSERT_TRUE(client_msg.has_invalidation_ack_message());
+
+ InvalidationMessage expected_msg;
+ // The client should strip the payload from the invalidation.
+ invalidations[0].clear_payload();
+ InitInvalidationMessage(invalidations, &expected_msg);
+ const InvalidationMessage& actual_msg =
+ client_msg.invalidation_ack_message();
+ ASSERT_TRUE(CompareMessages(expected_msg, actual_msg));
+}
+
+// Give a registration sync request message and an info request message to the
+// client and wait for the sync message and the info message to go out.
+TEST_F(InvalidationClientImplTest, ServerRequests) {
+ // Set some expectations for starting the client.
+ SetExpectationsForTiclStart(2);
+
+ // Start the ticl.
+ StartClient();
+
+ // Make the server to client message.
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+
+ // 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);
+
+ // Give it to the prototol handler.
+ ProcessIncomingMessage(message, EndOfTestWaitTime());
+
+ // Make sure that the message is as expected.
+ ClientToServerMessage client_msg;
+ client_msg.ParseFromString(outgoing_messages[1]);
+ ASSERT_TRUE(client_msg.has_info_message());
+ ASSERT_TRUE(client_msg.has_registration_sync_message());
+}
+
+// Tests that an incoming unknown failure message results in the app being
+// informed about it.
+TEST_F(InvalidationClientImplTest, IncomingErrorMessage) {
+ SetExpectationsForTiclStart(1);
+
+ // Set up listener expectation for error.
+ EXPECT_CALL(listener, InformError(Eq(client.get()), _));
+
+ // Start the ticl.
+ StartClient();
+
+ // Give the error message to the protocol handler.
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+ InitErrorMessage(ErrorMessage_Code_UNKNOWN_FAILURE, "Some error message",
+ message.mutable_error_message());
+ ProcessIncomingMessage(message, EndOfTestWaitTime());
+}
+
+// Tests that an incoming auth failure message results in the app being informed
+// about it and the registrations being removed.
+TEST_F(InvalidationClientImplTest, IncomingAuthErrorMessage) {
+ SetExpectationsForTiclStart(2);
+
+ // One object to register for.
+ int num_objects = 1;
+ vector<ObjectIdP> oid_protos;
+ vector<ObjectId> oids;
+ InitTestObjectIds(num_objects, &oid_protos);
+ ConvertFromObjectIdProtos(oid_protos, &oids);
+
+ // Expect error and registration failure from the ticl.
+ EXPECT_CALL(listener, InformError(Eq(client.get()), _));
+ EXPECT_CALL(listener, InformRegistrationFailure(Eq(client.get()), Eq(oids[0]),
+ Eq(false), _));
+
+ // Start the client.
+ StartClient();
+
+ // Register and let the message be sent out.
+ client.get()->Register(oids[0]);
+ internal_scheduler->PassTime(
+ GetMaxBatchingDelay(config.protocol_handler_config()));
+
+ // Give this message to the protocol handler.
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+ InitErrorMessage(ErrorMessage_Code_AUTH_FAILURE, "Auth error message",
+ message.mutable_error_message());
+ ProcessIncomingMessage(message, EndOfTestWaitTime());
+}
+
+// Tests that a registration that times out results in a reg sync message being
+// sent out.
+TEST_F(InvalidationClientImplTest, NetworkTimeouts) {
+ // Set some expectations for starting the client.
+ SetExpectationsForTiclStart(3);
+
+ // One object to register for.
+ int num_objects = 1;
+ vector<ObjectIdP> oid_protos;
+ vector<ObjectId> oids;
+ InitTestObjectIds(num_objects, &oid_protos);
+ ConvertFromObjectIdProtos(oid_protos, &oids);
+
+ // Start the client.
+ StartClient();
+
+ // Register for an object.
+ client.get()->Register(oids[0]);
+
+ // Let the registration message be sent out.
+ internal_scheduler->PassTime(
+ GetMaxBatchingDelay(config.protocol_handler_config()));
+
+ // Now let the network timeout occur and an info message be sent.
+ TimeDelta timeout_delay = GetMaxDelay(config.network_timeout_delay_ms());
+ internal_scheduler->PassTime(timeout_delay);
+
+ // Check that the message sent out is an info message asking for the server's
+ // summary.
+ ClientToServerMessage client_msg2;
+ client_msg2.ParseFromString(outgoing_messages[2]);
+ ASSERT_TRUE(client_msg2.has_info_message());
+ ASSERT_TRUE(
+ client_msg2.info_message().server_registration_summary_requested());
+ internal_scheduler->PassTime(EndOfTestWaitTime());
+}
+
+// Tests that an incoming message without registration summary does not
+// cause the registration summary in the client to be changed.
+TEST_F(InvalidationClientImplTest, NoRegistrationSummary) {
+ // Test plan: Initialze the ticl, let it get a token with a ServerToClient
+ // message that has no registration summary.
+
+ // Set some expectations for starting the client and start the client.
+ // Give it a summary with 1 reg.
+ reg_summary.get()->set_num_registrations(1);
+ SetExpectationsForTiclStart(1);
+ StartClient();
+
+ // Now give it an message with no summary. It should not reset to a summary
+ // with zero registrations.
+ reg_summary.reset(NULL);
+ ServerToClientMessage message;
+ InitServerHeader(client.get()->GetClientToken(), message.mutable_header());
+ ProcessIncomingMessage(message, EndOfTestWaitTime());
+
+ // Check that the registration manager state did not change.
+ string manager_serial_state;
+ client->GetRegistrationManagerStateAsSerializedProto(&manager_serial_state);
+ RegistrationManagerStateP reg_manager_state;
+ reg_manager_state.ParseFromString(manager_serial_state);
+
+ // Check that the registration manager state's number of registrations is 1.
+ TLOG(logger, INFO, "Reg manager state: %s",
+ ProtoHelpers::ToString(reg_manager_state).c_str());
+ ASSERT_EQ(1, reg_manager_state.server_summary().num_registrations());
+}
+
+// Tests that heartbeats are sent out as time advances.
+TEST_F(InvalidationClientImplTest, Heartbeats) {
+ // Set some expectations for starting the client.
+ SetExpectationsForTiclStart(2);
+
+ // Start the client.
+ StartClient();
+
+ // Now let the heartbeat occur and an info message be sent.
+ TimeDelta heartbeat_delay = GetMaxDelay(config.heartbeat_interval_ms() +
+ config.protocol_handler_config().batching_delay_ms());
+ internal_scheduler->PassTime(heartbeat_delay);
+
+ // Check that the heartbeat is sent and it does not ask for the server's
+ // summary.
+ ClientToServerMessage client_msg1;
+ client_msg1.ParseFromString(outgoing_messages[1]);
+ ASSERT_TRUE(client_msg1.has_info_message());
+ ASSERT_FALSE(
+ client_msg1.info_message().server_registration_summary_requested());
+ internal_scheduler->PassTime(EndOfTestWaitTime());
+}
+
+} // namespace invalidation

Powered by Google App Engine
This is Rietveld 408576698