telemetry_log_writer_unittest.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/base/telemetry_log_writer.h"
  5. #include <array>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/containers/circular_deque.h"
  9. #include "base/logging.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "base/run_loop.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/timer/timer.h"
  14. #include "net/http/http_status_code.h"
  15. #include "remoting/base/chromoting_event.h"
  16. #include "remoting/base/fake_oauth_token_getter.h"
  17. #include "remoting/base/protobuf_http_status.h"
  18. #include "remoting/base/protobuf_http_test_responder.h"
  19. #include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
  20. #include "testing/gmock/include/gmock/gmock.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. namespace remoting {
  23. namespace {
  24. MATCHER_P(HasDurations, durations, "") {
  25. apis::v1::CreateEventRequest request;
  26. EXPECT_TRUE(ProtobufHttpTestResponder::ParseRequestMessage(arg, &request));
  27. if (!request.has_payload() ||
  28. static_cast<std::size_t>(request.payload().events_size()) !=
  29. durations.size()) {
  30. return false;
  31. }
  32. for (std::size_t i = 0; i < durations.size(); ++i) {
  33. auto event = request.payload().events(i);
  34. if (!event.has_session_duration() ||
  35. event.session_duration() != durations[i]) {
  36. return false;
  37. }
  38. }
  39. return true;
  40. }
  41. template <typename... Args>
  42. std::array<int, sizeof...(Args)> MakeIntArray(Args&&... args) {
  43. return {std::forward<Args>(args)...};
  44. }
  45. // Sets expectation for call to CreateEvent with the set of events specified,
  46. // identified by their session_duration field. (Session duration is incremented
  47. // after each call to LogFakeEvent.)
  48. //
  49. // responder: The ProtobufHttpTestResponder on which to set the expectation.
  50. // durations: The durations of the expected events, grouped with parentheses.
  51. // E.g., (0) or (1, 2).
  52. //
  53. // Example usage:
  54. // EXPECT_EVENTS(test_responder_, (1, 2))
  55. // .WillOnce(DoSucceed(&test_responder_));
  56. #define EXPECT_EVENTS(responder, durations) \
  57. EXPECT_CALL((responder.GetMockInterceptor()), \
  58. Run(HasDurations(MakeIntArray durations)))
  59. // Creates a success action to be passed to WillOnce and friends.
  60. decltype(auto) DoSucceed(ProtobufHttpTestResponder* responder) {
  61. return [responder](const network::ResourceRequest& request) {
  62. return responder->AddResponse(request.url.spec(),
  63. apis::v1::CreateEventResponse());
  64. };
  65. }
  66. // Creates a failure action to be passed to WillOnce and friends.
  67. decltype(auto) DoFail(ProtobufHttpTestResponder* responder) {
  68. return [responder](const network::ResourceRequest& request) {
  69. return responder->AddError(
  70. request.url.spec(),
  71. ProtobufHttpStatus(ProtobufHttpStatus::Code::UNAVAILABLE,
  72. "The service is unavailable."));
  73. };
  74. }
  75. } // namespace
  76. class TelemetryLogWriterTest : public testing::Test {
  77. public:
  78. TelemetryLogWriterTest() {
  79. log_writer_.Init(test_responder_.GetUrlLoaderFactory());
  80. }
  81. ~TelemetryLogWriterTest() override {
  82. // It's an async process to create request to send all pending events.
  83. RunUntilIdle();
  84. }
  85. protected:
  86. void LogFakeEvent() {
  87. ChromotingEvent entry;
  88. entry.SetInteger(ChromotingEvent::kSessionDurationKey, duration_);
  89. duration_++;
  90. log_writer_.Log(entry);
  91. }
  92. // Waits until TelemetryLog is idle.
  93. void RunUntilIdle() {
  94. // gRPC has its own event loop, which means sometimes the task queue will
  95. // be empty while gRPC is working. Thus, TaskEnvironment::RunUntilIdle can't
  96. // be used, as it would return early. Instead, TelemetryLogWriter is polled
  97. // to determine when it has finished.
  98. base::RunLoop run_loop;
  99. base::RepeatingTimer timer;
  100. // Mock clock will auto-fast-forward, so the delay here is somewhat
  101. // arbitrary.
  102. timer.Start(
  103. FROM_HERE, base::Seconds(1),
  104. base::BindRepeating(
  105. [](TelemetryLogWriter* log_writer,
  106. base::RepeatingClosure quit_closure) {
  107. if (log_writer->IsIdleForTesting()) {
  108. quit_closure.Run();
  109. }
  110. },
  111. base::Unretained(&log_writer_), run_loop.QuitWhenIdleClosure()));
  112. run_loop.Run();
  113. }
  114. ProtobufHttpTestResponder test_responder_;
  115. TelemetryLogWriter log_writer_{
  116. std::make_unique<FakeOAuthTokenGetter>(OAuthTokenGetter::SUCCESS,
  117. "dummy",
  118. "dummy")};
  119. private:
  120. // Incremented for each event to allow them to be distinguished.
  121. int duration_ = 0;
  122. // MOCK_TIME will fast forward through back-off delays.
  123. base::test::SingleThreadTaskEnvironment task_environment_{
  124. base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
  125. };
  126. TEST_F(TelemetryLogWriterTest, PostOneLogImmediately) {
  127. EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoSucceed(&test_responder_));
  128. LogFakeEvent();
  129. }
  130. TEST_F(TelemetryLogWriterTest, PostOneLogAndHaveTwoPendingLogs) {
  131. ::testing::InSequence sequence;
  132. // First one is sent right away. Second two are batched and sent once the
  133. // first request has completed.
  134. EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoSucceed(&test_responder_));
  135. EXPECT_EVENTS(test_responder_, (1, 2)).WillOnce(DoSucceed(&test_responder_));
  136. LogFakeEvent();
  137. LogFakeEvent();
  138. LogFakeEvent();
  139. }
  140. TEST_F(TelemetryLogWriterTest, PostLogFailedAndRetry) {
  141. EXPECT_EVENTS(test_responder_, (0))
  142. .Times(5)
  143. .WillRepeatedly(DoFail(&test_responder_));
  144. LogFakeEvent();
  145. }
  146. TEST_F(TelemetryLogWriterTest, PostOneLogFailedResendWithTwoPendingLogs) {
  147. EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoFail(&test_responder_));
  148. EXPECT_EVENTS(test_responder_, (0, 1, 2))
  149. .WillOnce(DoSucceed(&test_responder_));
  150. LogFakeEvent();
  151. LogFakeEvent();
  152. LogFakeEvent();
  153. }
  154. TEST_F(TelemetryLogWriterTest, PostThreeLogsFailedAndResendWithOnePending) {
  155. // This tests the ordering of the resent log.
  156. EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoFail(&test_responder_));
  157. EXPECT_EVENTS(test_responder_, (0, 1, 2))
  158. .WillOnce(testing::DoAll(
  159. testing::InvokeWithoutArgs([this]() { LogFakeEvent(); }),
  160. DoFail(&test_responder_)));
  161. EXPECT_EVENTS(test_responder_, (0, 1, 2, 3))
  162. .WillOnce(DoSucceed(&test_responder_));
  163. LogFakeEvent();
  164. LogFakeEvent();
  165. LogFakeEvent();
  166. }
  167. TEST_F(TelemetryLogWriterTest, PostOneFailedThenSucceed) {
  168. EXPECT_EVENTS(test_responder_, (0))
  169. .WillOnce(DoFail(&test_responder_))
  170. .WillOnce(DoSucceed(&test_responder_));
  171. LogFakeEvent();
  172. }
  173. } // namespace remoting