Chromium Code Reviews| Index: google_apis/gcm/engine/mcs_client_unittest.cc |
| diff --git a/google_apis/gcm/engine/mcs_client_unittest.cc b/google_apis/gcm/engine/mcs_client_unittest.cc |
| index 0dcf2989b76137a38a431af91413830b716afdf9..bbf3bf494764d453a9b249afc635b1bf7b665e33 100644 |
| --- a/google_apis/gcm/engine/mcs_client_unittest.cc |
| +++ b/google_apis/gcm/engine/mcs_client_unittest.cc |
| @@ -8,6 +8,7 @@ |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| +#include "base/test/simple_test_clock.h" |
| #include "components/webdata/encryptor/encryptor.h" |
| #include "google_apis/gcm/base/mcs_util.h" |
| #include "google_apis/gcm/engine/fake_connection_factory.h" |
| @@ -30,26 +31,34 @@ const int kMessageBatchSize = 6; |
| // TODO(zea): get this (and other constants) directly from the mcs client. |
| const int kAckLimitSize = 10; |
| +// TTL value for reliable messages. |
| +const int kTTLValue = 5 * 60; // 5 minutes. |
| + |
| // Helper for building arbitrary data messages. |
| MCSMessage BuildDataMessage(const std::string& from, |
| const std::string& category, |
| int last_stream_id_received, |
| - const std::string persistent_id) { |
| + const std::string persistent_id, |
| + int ttl, |
| + uint64 sent) { |
| mcs_proto::DataMessageStanza data_message; |
| data_message.set_from(from); |
| data_message.set_category(category); |
| data_message.set_last_stream_id_received(last_stream_id_received); |
| if (!persistent_id.empty()) |
| data_message.set_persistent_id(persistent_id); |
| + data_message.set_ttl(ttl); |
| + data_message.set_sent(sent); |
| return MCSMessage(kDataMessageStanzaTag, data_message); |
| } |
| // MCSClient with overriden exposed persistent id logic. |
| class TestMCSClient : public MCSClient { |
| public: |
| - TestMCSClient(ConnectionFactory* connection_factory, |
| + TestMCSClient(base::Clock* clock, |
| + ConnectionFactory* connection_factory, |
| RMQStore* rmq_store) |
| - : MCSClient(connection_factory, rmq_store), |
| + : MCSClient(clock, connection_factory, rmq_store), |
| next_id_(0) { |
| } |
| @@ -70,6 +79,7 @@ class MCSClientTest : public testing::Test { |
| void InitializeClient(); |
| void LoginClient(const std::vector<std::string>& acknowledged_ids); |
| + base::SimpleTestClock* clock() { return &clock_; } |
| TestMCSClient* mcs_client() const { return mcs_client_.get(); } |
| FakeConnectionFactory* connection_factory() { |
| return &connection_factory_; |
| @@ -92,6 +102,8 @@ class MCSClientTest : public testing::Test { |
| void MessageReceivedCallback(const MCSMessage& message); |
| void MessageSentCallback(const std::string& message_id); |
| + base::SimpleTestClock clock_; |
| + |
| base::ScopedTempDir temp_directory_; |
| base::MessageLoop message_loop_; |
| scoped_ptr<base::RunLoop> run_loop_; |
| @@ -125,7 +137,9 @@ MCSClientTest::~MCSClientTest() {} |
| void MCSClientTest::BuildMCSClient() { |
| rmq_store_.reset(new RMQStore(temp_directory_.path(), |
| message_loop_.message_loop_proxy())); |
| - mcs_client_.reset(new TestMCSClient(&connection_factory_, rmq_store_.get())); |
| + mcs_client_.reset(new TestMCSClient(&clock_, |
| + &connection_factory_, |
| + rmq_store_.get())); |
| } |
| void MCSClientTest::InitializeClient() { |
| @@ -189,6 +203,7 @@ void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) { |
| void MCSClientTest::MessageSentCallback(const std::string& message_id) { |
| DVLOG(1) << "Message sent callback invoked, killing loop."; |
| + sent_message_id_ = message_id; |
| run_loop_->Quit(); |
| } |
| @@ -243,21 +258,40 @@ TEST_F(MCSClientTest, SendMessageNoRMQ) { |
| BuildMCSClient(); |
| InitializeClient(); |
| LoginClient(std::vector<std::string>()); |
| - MCSMessage message(BuildDataMessage("from", "category", 1, "")); |
| + MCSMessage message(BuildDataMessage("from", "category", 1, "", 0, 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, false); |
| + mcs_client()->SendMessage(message); |
| + EXPECT_TRUE(GetFakeHandler()-> |
| + AllOutgoingMessagesReceived()); |
| +} |
| + |
| +// Send a message without RMQ support while disconnected. Message send should |
| +// fail immediately, invoking callback. |
| +TEST_F(MCSClientTest, SendMessageNoRMQWhileDisconnected) { |
| + BuildMCSClient(); |
| + InitializeClient(); |
| + |
| + EXPECT_TRUE(sent_message_id().empty()); |
| + MCSMessage message(BuildDataMessage("from", "category", 1, "", 0, 0)); |
| + mcs_client()->SendMessage(message); |
| + |
| + // Message sent callback should be invoked, but no message should actually |
| + // be sent. |
| + EXPECT_FALSE(sent_message_id().empty()); |
| EXPECT_TRUE(GetFakeHandler()-> |
|
fgorski
2013/12/28 01:15:08
one line
Nicolas Zea
2013/12/30 21:46:19
Done.
|
| AllOutgoingMessagesReceived()); |
| } |
| + |
| // Send a message with RMQ support. |
| TEST_F(MCSClientTest, SendMessageRMQ) { |
| BuildMCSClient(); |
| InitializeClient(); |
| LoginClient(std::vector<std::string>()); |
| - MCSMessage message(BuildDataMessage("from", "category", 1, "1")); |
| + MCSMessage message( |
| + BuildDataMessage("from", "category", 1, "1", kTTLValue, 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| } |
| @@ -269,7 +303,8 @@ TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) { |
| InitializeClient(); |
| LoginClient(std::vector<std::string>()); |
| GetFakeHandler()->set_fail_send(true); |
| - MCSMessage message(BuildDataMessage("from", "category", 1, "1")); |
| + MCSMessage message( |
| + BuildDataMessage("from", "category", 1, "1", kTTLValue, 0)); |
| // The initial (failed) send. |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| @@ -280,7 +315,7 @@ TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) { |
| PassAs<const google::protobuf::MessageLite>())); |
| // The second (re)send. |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| EXPECT_FALSE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| GetFakeHandler()->set_fail_send(false); |
| @@ -298,12 +333,13 @@ TEST_F(MCSClientTest, SendMessageRMQOnRestart) { |
| InitializeClient(); |
| LoginClient(std::vector<std::string>()); |
| GetFakeHandler()->set_fail_send(true); |
| - MCSMessage message(BuildDataMessage("from", "category", 1, "1")); |
| + MCSMessage message( |
| + BuildDataMessage("from", "category", 1, "1", kTTLValue, 0)); |
| // The initial (failed) send. |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| GetFakeHandler()->set_fail_send(false); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| @@ -327,9 +363,14 @@ TEST_F(MCSClientTest, SendMessageRMQWithStreamAck) { |
| // Send some messages. |
| for (int i = 1; i <= kMessageBatchSize; ++i) { |
| MCSMessage message( |
| - BuildDataMessage("from", "category", 1, base::IntToString(i))); |
| + BuildDataMessage("from", |
| + "category", |
| + 1, |
| + base::IntToString(i), |
| + kTTLValue, |
| + 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| } |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| @@ -361,9 +402,9 @@ TEST_F(MCSClientTest, SendMessageRMQAckOnReconnect) { |
| for (int i = 1; i <= kMessageBatchSize; ++i) { |
| id_list.push_back(base::IntToString(i)); |
| MCSMessage message( |
| - BuildDataMessage("from", "category", 1, id_list.back())); |
| + BuildDataMessage("from", "category", 1, id_list.back(), kTTLValue, 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| } |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| @@ -395,9 +436,9 @@ TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) { |
| for (int i = 1; i <= kMessageBatchSize; ++i) { |
| id_list.push_back(base::IntToString(i)); |
| MCSMessage message( |
| - BuildDataMessage("from", "category", 1, id_list.back())); |
| + BuildDataMessage("from", "category", 1, id_list.back(), kTTLValue, 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| } |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| @@ -420,7 +461,9 @@ TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) { |
| BuildDataMessage("from", |
| "category", |
| 2, |
| - remaining_ids[i - 1])); |
| + remaining_ids[i - 1], |
| + kTTLValue, |
| + 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| } |
| scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids)); |
| @@ -444,7 +487,7 @@ TEST_F(MCSClientTest, AckOnLogin) { |
| for (int i = 1; i <= kMessageBatchSize; ++i) { |
| id_list.push_back(base::IntToString(i)); |
| MCSMessage message( |
| - BuildDataMessage("from", "category", i, id_list.back())); |
| + BuildDataMessage("from", "category", i, id_list.back(), kTTLValue, 0)); |
| GetFakeHandler()->ReceiveMessage(message); |
| WaitForMCSEvent(); |
| PumpLoop(); |
| @@ -468,7 +511,7 @@ TEST_F(MCSClientTest, AckOnSend) { |
| for (int i = 1; i <= kMessageBatchSize; ++i) { |
| id_list.push_back(base::IntToString(i)); |
| MCSMessage message( |
| - BuildDataMessage("from", "category", i, id_list.back())); |
| + BuildDataMessage("from", "category", i, id_list.back(), kTTLValue, 0)); |
| GetFakeHandler()->ReceiveMessage(message); |
| WaitForMCSEvent(); |
| PumpLoop(); |
| @@ -476,9 +519,14 @@ TEST_F(MCSClientTest, AckOnSend) { |
| // Trigger a message send, which should acknowledge via stream ack. |
| MCSMessage message( |
| - BuildDataMessage("from", "category", kMessageBatchSize + 1, "1")); |
| + BuildDataMessage("from", |
| + "category", |
| + kMessageBatchSize + 1, |
| + "1", |
| + kTTLValue, |
| + 0)); |
| GetFakeHandler()->ExpectOutgoingMessage(message); |
| - mcs_client()->SendMessage(message, true); |
| + mcs_client()->SendMessage(message); |
| EXPECT_TRUE(GetFakeHandler()-> |
| AllOutgoingMessagesReceived()); |
| } |
| @@ -502,7 +550,7 @@ TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) { |
| for (int i = 1; i <= kAckLimitSize; ++i) { |
| id_list.push_back(base::IntToString(i)); |
| MCSMessage message( |
| - BuildDataMessage("from", "category", i, id_list.back())); |
| + BuildDataMessage("from", "category", i, id_list.back(), kTTLValue, 0)); |
| GetFakeHandler()->ReceiveMessage(message); |
| WaitForMCSEvent(); |
| PumpLoop(); |
| @@ -537,6 +585,53 @@ TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) { |
| AllOutgoingMessagesReceived()); |
| } |
| +// If a message's TTL has expired by the time it reaches the front of the send |
| +// queue, it should be dropped. |
| +TEST_F(MCSClientTest, ExpiredTTLOnSend) { |
| + BuildMCSClient(); |
| + InitializeClient(); |
| + LoginClient(std::vector<std::string>()); |
| + MCSMessage message( |
| + BuildDataMessage("from", "category", 1, "1", kTTLValue, 0)); |
| + |
| + // Advance time to after the TTL. |
| + clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 1)); |
| + EXPECT_TRUE(sent_message_id().empty()); |
| + mcs_client()->SendMessage(message); |
| + |
| + // No messages should be sent, but the callback should still be invoked. |
| + EXPECT_FALSE(sent_message_id().empty()); |
| + EXPECT_TRUE(GetFakeHandler()-> |
|
fgorski
2013/12/28 01:15:08
one line. fix other places.
Nicolas Zea
2013/12/30 21:46:19
Done.
|
| + AllOutgoingMessagesReceived()); |
| +} |
| + |
| +TEST_F(MCSClientTest, ExpiredTTLOnRestart) { |
| + BuildMCSClient(); |
| + InitializeClient(); |
| + LoginClient(std::vector<std::string>()); |
| + GetFakeHandler()->set_fail_send(true); |
| + MCSMessage message( |
| + BuildDataMessage("from", "category", 1, "1", kTTLValue, 0)); |
| + |
| + // The initial (failed) send. |
| + GetFakeHandler()->ExpectOutgoingMessage(message); |
| + GetFakeHandler()->set_fail_send(false); |
| + mcs_client()->SendMessage(message); |
| + EXPECT_TRUE(GetFakeHandler()-> |
| + AllOutgoingMessagesReceived()); |
| + |
| + // Move the clock forward and rebuild the client, which should fail the |
| + // message send on restart. |
| + clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 1)); |
| + BuildMCSClient(); |
| + InitializeClient(); |
| + LoginClient(std::vector<std::string>()); |
| + PumpLoop(); |
| + EXPECT_FALSE(sent_message_id().empty()); |
| + EXPECT_TRUE(GetFakeHandler()-> |
| + AllOutgoingMessagesReceived()); |
| +} |
| + |
| } // namespace |
| } // namespace gcm |