123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "remoting/base/telemetry_log_writer.h"
- #include <array>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/containers/circular_deque.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/run_loop.h"
- #include "base/test/task_environment.h"
- #include "base/timer/timer.h"
- #include "net/http/http_status_code.h"
- #include "remoting/base/chromoting_event.h"
- #include "remoting/base/fake_oauth_token_getter.h"
- #include "remoting/base/protobuf_http_status.h"
- #include "remoting/base/protobuf_http_test_responder.h"
- #include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace remoting {
- namespace {
- MATCHER_P(HasDurations, durations, "") {
- apis::v1::CreateEventRequest request;
- EXPECT_TRUE(ProtobufHttpTestResponder::ParseRequestMessage(arg, &request));
- if (!request.has_payload() ||
- static_cast<std::size_t>(request.payload().events_size()) !=
- durations.size()) {
- return false;
- }
- for (std::size_t i = 0; i < durations.size(); ++i) {
- auto event = request.payload().events(i);
- if (!event.has_session_duration() ||
- event.session_duration() != durations[i]) {
- return false;
- }
- }
- return true;
- }
- template <typename... Args>
- std::array<int, sizeof...(Args)> MakeIntArray(Args&&... args) {
- return {std::forward<Args>(args)...};
- }
- // Sets expectation for call to CreateEvent with the set of events specified,
- // identified by their session_duration field. (Session duration is incremented
- // after each call to LogFakeEvent.)
- //
- // responder: The ProtobufHttpTestResponder on which to set the expectation.
- // durations: The durations of the expected events, grouped with parentheses.
- // E.g., (0) or (1, 2).
- //
- // Example usage:
- // EXPECT_EVENTS(test_responder_, (1, 2))
- // .WillOnce(DoSucceed(&test_responder_));
- #define EXPECT_EVENTS(responder, durations) \
- EXPECT_CALL((responder.GetMockInterceptor()), \
- Run(HasDurations(MakeIntArray durations)))
- // Creates a success action to be passed to WillOnce and friends.
- decltype(auto) DoSucceed(ProtobufHttpTestResponder* responder) {
- return [responder](const network::ResourceRequest& request) {
- return responder->AddResponse(request.url.spec(),
- apis::v1::CreateEventResponse());
- };
- }
- // Creates a failure action to be passed to WillOnce and friends.
- decltype(auto) DoFail(ProtobufHttpTestResponder* responder) {
- return [responder](const network::ResourceRequest& request) {
- return responder->AddError(
- request.url.spec(),
- ProtobufHttpStatus(ProtobufHttpStatus::Code::UNAVAILABLE,
- "The service is unavailable."));
- };
- }
- } // namespace
- class TelemetryLogWriterTest : public testing::Test {
- public:
- TelemetryLogWriterTest() {
- log_writer_.Init(test_responder_.GetUrlLoaderFactory());
- }
- ~TelemetryLogWriterTest() override {
- // It's an async process to create request to send all pending events.
- RunUntilIdle();
- }
- protected:
- void LogFakeEvent() {
- ChromotingEvent entry;
- entry.SetInteger(ChromotingEvent::kSessionDurationKey, duration_);
- duration_++;
- log_writer_.Log(entry);
- }
- // Waits until TelemetryLog is idle.
- void RunUntilIdle() {
- // gRPC has its own event loop, which means sometimes the task queue will
- // be empty while gRPC is working. Thus, TaskEnvironment::RunUntilIdle can't
- // be used, as it would return early. Instead, TelemetryLogWriter is polled
- // to determine when it has finished.
- base::RunLoop run_loop;
- base::RepeatingTimer timer;
- // Mock clock will auto-fast-forward, so the delay here is somewhat
- // arbitrary.
- timer.Start(
- FROM_HERE, base::Seconds(1),
- base::BindRepeating(
- [](TelemetryLogWriter* log_writer,
- base::RepeatingClosure quit_closure) {
- if (log_writer->IsIdleForTesting()) {
- quit_closure.Run();
- }
- },
- base::Unretained(&log_writer_), run_loop.QuitWhenIdleClosure()));
- run_loop.Run();
- }
- ProtobufHttpTestResponder test_responder_;
- TelemetryLogWriter log_writer_{
- std::make_unique<FakeOAuthTokenGetter>(OAuthTokenGetter::SUCCESS,
- "dummy",
- "dummy")};
- private:
- // Incremented for each event to allow them to be distinguished.
- int duration_ = 0;
- // MOCK_TIME will fast forward through back-off delays.
- base::test::SingleThreadTaskEnvironment task_environment_{
- base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
- };
- TEST_F(TelemetryLogWriterTest, PostOneLogImmediately) {
- EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoSucceed(&test_responder_));
- LogFakeEvent();
- }
- TEST_F(TelemetryLogWriterTest, PostOneLogAndHaveTwoPendingLogs) {
- ::testing::InSequence sequence;
- // First one is sent right away. Second two are batched and sent once the
- // first request has completed.
- EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoSucceed(&test_responder_));
- EXPECT_EVENTS(test_responder_, (1, 2)).WillOnce(DoSucceed(&test_responder_));
- LogFakeEvent();
- LogFakeEvent();
- LogFakeEvent();
- }
- TEST_F(TelemetryLogWriterTest, PostLogFailedAndRetry) {
- EXPECT_EVENTS(test_responder_, (0))
- .Times(5)
- .WillRepeatedly(DoFail(&test_responder_));
- LogFakeEvent();
- }
- TEST_F(TelemetryLogWriterTest, PostOneLogFailedResendWithTwoPendingLogs) {
- EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoFail(&test_responder_));
- EXPECT_EVENTS(test_responder_, (0, 1, 2))
- .WillOnce(DoSucceed(&test_responder_));
- LogFakeEvent();
- LogFakeEvent();
- LogFakeEvent();
- }
- TEST_F(TelemetryLogWriterTest, PostThreeLogsFailedAndResendWithOnePending) {
- // This tests the ordering of the resent log.
- EXPECT_EVENTS(test_responder_, (0)).WillOnce(DoFail(&test_responder_));
- EXPECT_EVENTS(test_responder_, (0, 1, 2))
- .WillOnce(testing::DoAll(
- testing::InvokeWithoutArgs([this]() { LogFakeEvent(); }),
- DoFail(&test_responder_)));
- EXPECT_EVENTS(test_responder_, (0, 1, 2, 3))
- .WillOnce(DoSucceed(&test_responder_));
- LogFakeEvent();
- LogFakeEvent();
- LogFakeEvent();
- }
- TEST_F(TelemetryLogWriterTest, PostOneFailedThenSucceed) {
- EXPECT_EVENTS(test_responder_, (0))
- .WillOnce(DoFail(&test_responder_))
- .WillOnce(DoSucceed(&test_responder_));
- LogFakeEvent();
- }
- } // namespace remoting
|