<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "api/rtc_event_log/rtc_event_log.h"
#include "api/rtc_event_log/rtc_event_log_factory.h"
#include "api/rtc_event_log_output_file.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
#include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h"
#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h"
#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h"
#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "logging/rtc_event_log/rtc_event_log_unittest_helper.h"
#include "logging/rtc_event_log/rtc_stream_config.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "rtc_base/checks.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/random.h"
#include "test/gtest.h"
#include "test/testsupport/file_utils.h"

namespace webrtc {

namespace {

struct EventCounts {
  size_t audio_send_streams = 0;
  size_t audio_recv_streams = 0;
  size_t video_send_streams = 0;
  size_t video_recv_streams = 0;
  size_t alr_states = 0;
  size_t route_changes = 0;
  size_t audio_playouts = 0;
  size_t ana_configs = 0;
  size_t bwe_loss_events = 0;
  size_t bwe_delay_events = 0;
  size_t dtls_transport_states = 0;
  size_t dtls_writable_states = 0;
  size_t frame_decoded_events = 0;
  size_t probe_creations = 0;
  size_t probe_successes = 0;
  size_t probe_failures = 0;
  size_t ice_configs = 0;
  size_t ice_events = 0;
  size_t incoming_rtp_packets = 0;
  size_t outgoing_rtp_packets = 0;
  size_t incoming_rtcp_packets = 0;
  size_t outgoing_rtcp_packets = 0;
  size_t generic_packets_sent = 0;
  size_t generic_packets_received = 0;
  size_t generic_acks_received = 0;

  size_t total_nonconfig_events() const {
    return alr_states + route_changes + audio_playouts + ana_configs +
           bwe_loss_events + bwe_delay_events + dtls_transport_states +
           dtls_writable_states + frame_decoded_events + probe_creations +
           probe_successes + probe_failures + ice_configs + ice_events +
           incoming_rtp_packets + outgoing_rtp_packets + incoming_rtcp_packets +
           outgoing_rtcp_packets + generic_packets_sent +
           generic_packets_received + generic_acks_received;
  }

  size_t total_config_events() const {
    return audio_send_streams + audio_recv_streams + video_send_streams +
           video_recv_streams;
  }

  size_t total_events() const {
    return total_nonconfig_events() + total_config_events();
  }
};

class RtcEventLogSession
    : public ::testing::TestWithParam<
          std::tuple<uint64_t, int64_t, RtcEventLog::EncodingType>> {
 public:
  RtcEventLogSession()
      : seed_(std::get<0>(GetParam())),
        prng_(seed_),
        output_period_ms_(std::get<1>(GetParam())),
        encoding_type_(std::get<2>(GetParam())),
        gen_(seed_ * 880001UL),
        verifier_(encoding_type_) {
    clock_.SetTime(Timestamp::Micros(prng_.Rand<uint32_t>()));
    // Find the name of the current test, in order to use it as a temporary
    // filename.
    // TODO(terelius): Use a general utility function to generate a temp file.
    auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
    std::string test_name =
        std::string(test_info->test_case_name()) + "_" + test_info->name();
    std::replace(test_name.begin(), test_name.end(), '/', '_');
    temp_filename_ = test::OutputPath() + test_name;
  }

  // Create and buffer the config events and |num_events_before_log_start|
  // randomized non-config events. Then call StartLogging and finally create and
  // write the remaining non-config events.
  void WriteLog(EventCounts count, size_t num_events_before_log_start);
  void ReadAndVerifyLog();

  bool IsNewFormat() {
    return encoding_type_ == RtcEventLog::EncodingType::NewFormat;
  }

 private:
  void WriteAudioRecvConfigs(size_t audio_recv_streams, RtcEventLog* event_log);
  void WriteAudioSendConfigs(size_t audio_send_streams, RtcEventLog* event_log);
  void WriteVideoRecvConfigs(size_t video_recv_streams, RtcEventLog* event_log);
  void WriteVideoSendConfigs(size_t video_send_streams, RtcEventLog* event_log);

  std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> incoming_extensions_;
  std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> outgoing_extensions_;

  // Config events.
  std::vector<std::unique_ptr<RtcEventAudioSendStreamConfig>>
      audio_send_config_list_;
  std::vector<std::unique_ptr<RtcEventAudioReceiveStreamConfig>>
      audio_recv_config_list_;
  std::vector<std::unique_ptr<RtcEventVideoSendStreamConfig>>
      video_send_config_list_;
  std::vector<std::unique_ptr<RtcEventVideoReceiveStreamConfig>>
      video_recv_config_list_;

  // Regular events.
  std::vector<std::unique_ptr<RtcEventAlrState>> alr_state_list_;
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>>
      audio_playout_map_;  // Groups audio by SSRC.
  std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>
      ana_configs_list_;
  std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> bwe_delay_list_;
  std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> bwe_loss_list_;
  std::vector<std::unique_ptr<RtcEventDtlsTransportState>>
      dtls_transport_state_list_;
  std::vector<std::unique_ptr<RtcEventDtlsWritableState>>
      dtls_writable_state_list_;
  std::vector<std::unique_ptr<RtcEventFrameDecoded>> frame_decoded_event_list_;
  std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
      generic_acks_received_;
  std::vector<std::unique_ptr<RtcEventGenericPacketReceived>>
      generic_packets_received_;
  std::vector<std::unique_ptr<RtcEventGenericPacketSent>> generic_packets_sent_;
  std::vector<std::unique_ptr<RtcEventIceCandidatePair>> ice_event_list_;
  std::vector<std::unique_ptr<RtcEventIceCandidatePairConfig>> ice_config_list_;
  std::vector<std::unique_ptr<RtcEventProbeClusterCreated>>
      probe_creation_list_;
  std::vector<std::unique_ptr<RtcEventProbeResultFailure>> probe_failure_list_;
  std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_;
  std::vector<std::unique_ptr<RtcEventRouteChange>> route_change_list_;
  std::vector<std::unique_ptr<RtcEventRemoteEstimate>> remote_estimate_list_;
  std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> incoming_rtcp_list_;
  std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> outgoing_rtcp_list_;
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketIncoming>>>
      incoming_rtp_map_;  // Groups incoming RTP by SSRC.
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketOutgoing>>>
      outgoing_rtp_map_;  // Groups outgoing RTP by SSRC.

  int64_t start_time_us_;
  int64_t utc_start_time_us_;
  int64_t stop_time_us_;

  int64_t first_timestamp_ms_ = std::numeric_limits<int64_t>::max();
  int64_t last_timestamp_ms_ = std::numeric_limits<int64_t>::min();

  const uint64_t seed_;
  Random prng_;
  const int64_t output_period_ms_;
  const RtcEventLog::EncodingType encoding_type_;
  test::EventGenerator gen_;
  test::EventVerifier verifier_;
  rtc::ScopedFakeClock clock_;
  std::string temp_filename_;
};

bool SsrcUsed(
    uint32_t ssrc,
    const std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>>& streams) {
  for (const auto& kv : streams) {
    if (kv.first == ssrc)
      return true;
  }
  return false;
}

void RtcEventLogSession::WriteAudioRecvConfigs(size_t audio_recv_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  uint32_t ssrc;
  for (size_t i = 0; i < audio_recv_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, incoming_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    incoming_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewAudioReceiveStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    audio_recv_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteAudioSendConfigs(size_t audio_send_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  uint32_t ssrc;
  for (size_t i = 0; i < audio_send_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, outgoing_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    outgoing_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewAudioSendStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    audio_send_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteVideoRecvConfigs(size_t video_recv_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  RTC_CHECK_GE(video_recv_streams, 1);

  // Force least one stream to use all header extensions, to ensure
  // (statistically) that every extension is tested in packet creation.
  RtpHeaderExtensionMap all_extensions =
      ParsedRtcEventLog::GetDefaultHeaderExtensionMap();

  clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
  uint32_t ssrc = prng_.Rand<uint32_t>();
  incoming_extensions_.emplace_back(ssrc, all_extensions);
  auto event = gen_.NewVideoReceiveStreamConfig(ssrc, all_extensions);
  event_log->Log(event->Copy());
  video_recv_config_list_.push_back(std::move(event));
  for (size_t i = 1; i < video_recv_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, incoming_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    incoming_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    video_recv_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteVideoSendConfigs(size_t video_send_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  RTC_CHECK_GE(video_send_streams, 1);

  // Force least one stream to use all header extensions, to ensure
  // (statistically) that every extension is tested in packet creation.
  RtpHeaderExtensionMap all_extensions =
      ParsedRtcEventLog::GetDefaultHeaderExtensionMap();

  clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
  uint32_t ssrc = prng_.Rand<uint32_t>();
  outgoing_extensions_.emplace_back(ssrc, all_extensions);
  auto event = gen_.NewVideoSendStreamConfig(ssrc, all_extensions);
  event_log->Log(event->Copy());
  video_send_config_list_.push_back(std::move(event));
  for (size_t i = 1; i < video_send_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, outgoing_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    outgoing_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewVideoSendStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    video_send_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteLog(EventCounts count,
                                  size_t num_events_before_start) {
  // TODO(terelius): Allow test to run with either a real or a fake clock_.
  // Maybe always use the ScopedFakeClock, but conditionally SleepMs()?

  auto task_queue_factory = CreateDefaultTaskQueueFactory();
  RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get());
  // The log file will be flushed to disk when the event_log goes out of scope.
  std::unique_ptr<RtcEventLog> event_log =
      rtc_event_log_factory.CreateRtcEventLog(encoding_type_);

  // We can't send or receive packets without configured streams.
  RTC_CHECK_GE(count.video_recv_streams, 1);
  RTC_CHECK_GE(count.video_send_streams, 1);

  WriteAudioRecvConfigs(count.audio_recv_streams, event_log.get());
  WriteAudioSendConfigs(count.audio_send_streams, event_log.get());
  WriteVideoRecvConfigs(count.video_recv_streams, event_log.get());
  WriteVideoSendConfigs(count.video_send_streams, event_log.get());

  size_t remaining_events = count.total_nonconfig_events();
  ASSERT_LE(num_events_before_start, remaining_events);
  size_t remaining_events_at_start = remaining_events - num_events_before_start;
  for (; remaining_events > 0; remaining_events--) {
    if (remaining_events == remaining_events_at_start) {
      clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
      event_log->StartLogging(
          std::make_unique<RtcEventLogOutputFile>(temp_filename_, 10000000),
          output_period_ms_);
      start_time_us_ = rtc::TimeMicros();
      utc_start_time_us_ = rtc::TimeUTCMicros();
    }

    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    size_t selection = prng_.Rand(remaining_events - 1);
    first_timestamp_ms_ = std::min(first_timestamp_ms_, rtc::TimeMillis());
    last_timestamp_ms_ = std::max(last_timestamp_ms_, rtc::TimeMillis());

    if (selection < count.alr_states) {
      auto event = gen_.NewAlrState();
      event_log->Log(event->Copy());
      alr_state_list_.push_back(std::move(event));
      count.alr_states--;
      continue;
    }
    selection -= count.alr_states;

    if (selection < count.route_changes) {
      auto event = gen_.NewRouteChange();
      event_log->Log(event->Copy());
      route_change_list_.push_back(std::move(event));
      count.route_changes--;
      continue;
    }
    selection -= count.route_changes;

    if (selection < count.audio_playouts) {
      size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
      // This might be a video SSRC, but the parser does not use the config.
      uint32_t ssrc = incoming_extensions_[stream].first;
      auto event = gen_.NewAudioPlayout(ssrc);
      event_log->Log(event->Copy());
      audio_playout_map_[ssrc].push_back(std::move(event));
      count.audio_playouts--;
      continue;
    }
    selection -= count.audio_playouts;

    if (selection < count.ana_configs) {
      auto event = gen_.NewAudioNetworkAdaptation();
      event_log->Log(event->Copy());
      ana_configs_list_.push_back(std::move(event));
      count.ana_configs--;
      continue;
    }
    selection -= count.ana_configs;

    if (selection < count.bwe_loss_events) {
      auto event = gen_.NewBweUpdateLossBased();
      event_log->Log(event->Copy());
      bwe_loss_list_.push_back(std::move(event));
      count.bwe_loss_events--;
      continue;
    }
    selection -= count.bwe_loss_events;

    if (selection < count.bwe_delay_events) {
      auto event = gen_.NewBweUpdateDelayBased();
      event_log->Log(event->Copy());
      bwe_delay_list_.push_back(std::move(event));
      count.bwe_delay_events--;
      continue;
    }
    selection -= count.bwe_delay_events;

    if (selection < count.probe_creations) {
      auto event = gen_.NewProbeClusterCreated();
      event_log->Log(event->Copy());
      probe_creation_list_.push_back(std::move(event));
      count.probe_creations--;
      continue;
    }
    selection -= count.probe_creations;

    if (selection < count.probe_successes) {
      auto event = gen_.NewProbeResultSuccess();
      event_log->Log(event->Copy());
      probe_success_list_.push_back(std::move(event));
      count.probe_successes--;
      continue;
    }
    selection -= count.probe_successes;

    if (selection < count.probe_failures) {
      auto event = gen_.NewProbeResultFailure();
      event_log->Log(event->Copy());
      probe_failure_list_.push_back(std::move(event));
      count.probe_failures--;
      continue;
    }
    selection -= count.probe_failures;

    if (selection < count.dtls_transport_states) {
      auto event = gen_.NewDtlsTransportState();
      event_log->Log(event->Copy());
      dtls_transport_state_list_.push_back(std::move(event));
      count.dtls_transport_states--;
      continue;
    }
    selection -= count.dtls_transport_states;

    if (selection < count.dtls_writable_states) {
      auto event = gen_.NewDtlsWritableState();
      event_log->Log(event->Copy());
      dtls_writable_state_list_.push_back(std::move(event));
      count.dtls_writable_states--;
      continue;
    }
    selection -= count.dtls_writable_states;

    if (selection < count.frame_decoded_events) {
      auto event = gen_.NewFrameDecodedEvent();
      event_log->Log(event->Copy());
      frame_decoded_event_list_.push_back(std::move(event));
      count.frame_decoded_events--;
      continue;
    }
    selection -= count.frame_decoded_events;

    if (selection < count.ice_configs) {
      auto event = gen_.NewIceCandidatePairConfig();
      event_log->Log(event->Copy());
      ice_config_list_.push_back(std::move(event));
      count.ice_configs--;
      continue;
    }
    selection -= count.ice_configs;

    if (selection < count.ice_events) {
      auto event = gen_.NewIceCandidatePair();
      event_log->Log(event->Copy());
      ice_event_list_.push_back(std::move(event));
      count.ice_events--;
      continue;
    }
    selection -= count.ice_events;

    if (selection < count.incoming_rtp_packets) {
      size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
      uint32_t ssrc = incoming_extensions_[stream].first;
      auto event =
          gen_.NewRtpPacketIncoming(ssrc, incoming_extensions_[stream].second);
      event_log->Log(event->Copy());
      incoming_rtp_map_[ssrc].push_back(std::move(event));
      count.incoming_rtp_packets--;
      continue;
    }
    selection -= count.incoming_rtp_packets;

    if (selection < count.outgoing_rtp_packets) {
      size_t stream = prng_.Rand(outgoing_extensions_.size() - 1);
      uint32_t ssrc = outgoing_extensions_[stream].first;
      auto event =
          gen_.NewRtpPacketOutgoing(ssrc, outgoing_extensions_[stream].second);
      event_log->Log(event->Copy());
      outgoing_rtp_map_[ssrc].push_back(std::move(event));
      count.outgoing_rtp_packets--;
      continue;
    }
    selection -= count.outgoing_rtp_packets;

    if (selection < count.incoming_rtcp_packets) {
      auto event = gen_.NewRtcpPacketIncoming();
      event_log->Log(event->Copy());
      incoming_rtcp_list_.push_back(std::move(event));
      count.incoming_rtcp_packets--;
      continue;
    }
    selection -= count.incoming_rtcp_packets;

    if (selection < count.outgoing_rtcp_packets) {
      auto event = gen_.NewRtcpPacketOutgoing();
      event_log->Log(event->Copy());
      outgoing_rtcp_list_.push_back(std::move(event));
      count.outgoing_rtcp_packets--;
      continue;
    }
    selection -= count.outgoing_rtcp_packets;

    if (selection < count.generic_packets_sent) {
      auto event = gen_.NewGenericPacketSent();
      generic_packets_sent_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_packets_sent--;
      continue;
    }
    selection -= count.generic_packets_sent;

    if (selection < count.generic_packets_received) {
      auto event = gen_.NewGenericPacketReceived();
      generic_packets_received_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_packets_received--;
      continue;
    }
    selection -= count.generic_packets_received;

    if (selection < count.generic_acks_received) {
      auto event = gen_.NewGenericAckReceived();
      generic_acks_received_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_acks_received--;
      continue;
    }
    selection -= count.generic_acks_received;

    RTC_NOTREACHED();
  }

  event_log->StopLogging();
  stop_time_us_ = rtc::TimeMicros();

  ASSERT_EQ(count.total_nonconfig_events(), static_cast<size_t>(0));
}

// Read the file and verify that what we read back from the event log is the
// same as what we wrote down.
void RtcEventLogSession::ReadAndVerifyLog() {
  // Read the generated file from disk.
  ParsedRtcEventLog parsed_log;
  ASSERT_TRUE(parsed_log.ParseFile(temp_filename_).ok());

  // Start and stop events.
  auto& parsed_start_log_events = parsed_log.start_log_events();
  ASSERT_EQ(parsed_start_log_events.size(), static_cast<size_t>(1));
  verifier_.VerifyLoggedStartEvent(start_time_us_, utc_start_time_us_,
                                   parsed_start_log_events[0]);

  auto& parsed_stop_log_events = parsed_log.stop_log_events();
  ASSERT_EQ(parsed_stop_log_events.size(), static_cast<size_t>(1));
  verifier_.VerifyLoggedStopEvent(stop_time_us_, parsed_stop_log_events[0]);

  auto& parsed_alr_state_events = parsed_log.alr_state_events();
  ASSERT_EQ(parsed_alr_state_events.size(), alr_state_list_.size());
  for (size_t i = 0; i < parsed_alr_state_events.size(); i++) {
    verifier_.VerifyLoggedAlrStateEvent(*alr_state_list_[i],
                                        parsed_alr_state_events[i]);
  }
  auto& parsed_route_change_events = parsed_log.route_change_events();
  ASSERT_EQ(parsed_route_change_events.size(), route_change_list_.size());
  for (size_t i = 0; i < parsed_route_change_events.size(); i++) {
    verifier_.VerifyLoggedRouteChangeEvent(*route_change_list_[i],
                                           parsed_route_change_events[i]);
  }

  const auto& parsed_audio_playout_map = parsed_log.audio_playout_events();
  ASSERT_EQ(parsed_audio_playout_map.size(), audio_playout_map_.size());
  for (const auto& kv : parsed_audio_playout_map) {
    uint32_t ssrc = kv.first;
    const auto& parsed_audio_playout_stream = kv.second;
    const auto& audio_playout_stream = audio_playout_map_[ssrc];
    ASSERT_EQ(parsed_audio_playout_stream.size(), audio_playout_stream.size());
    for (size_t i = 0; i < parsed_audio_playout_map.size(); i++) {
      verifier_.VerifyLoggedAudioPlayoutEvent(*audio_playout_stream[i],
                                              parsed_audio_playout_stream[i]);
    }
  }

  auto& parsed_audio_network_adaptation_events =
      parsed_log.audio_network_adaptation_events();
  ASSERT_EQ(parsed_audio_network_adaptation_events.size(),
            ana_configs_list_.size());
  for (size_t i = 0; i < parsed_audio_network_adaptation_events.size(); i++) {
    verifier_.VerifyLoggedAudioNetworkAdaptationEvent(
        *ana_configs_list_[i], parsed_audio_network_adaptation_events[i]);
  }

  auto& parsed_bwe_delay_updates = parsed_log.bwe_delay_updates();
  ASSERT_EQ(parsed_bwe_delay_updates.size(), bwe_delay_list_.size());
  for (size_t i = 0; i < parsed_bwe_delay_updates.size(); i++) {
    verifier_.VerifyLoggedBweDelayBasedUpdate(*bwe_delay_list_[i],
                                              parsed_bwe_delay_updates[i]);
  }

  auto& parsed_bwe_loss_updates = parsed_log.bwe_loss_updates();
  ASSERT_EQ(parsed_bwe_loss_updates.size(), bwe_loss_list_.size());
  for (size_t i = 0; i < parsed_bwe_loss_updates.size(); i++) {
    verifier_.VerifyLoggedBweLossBasedUpdate(*bwe_loss_list_[i],
                                             parsed_bwe_loss_updates[i]);
  }

  auto& parsed_bwe_probe_cluster_created_events =
      parsed_log.bwe_probe_cluster_created_events();
  ASSERT_EQ(parsed_bwe_probe_cluster_created_events.size(),
            probe_creation_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_cluster_created_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeClusterCreatedEvent(
        *probe_creation_list_[i], parsed_bwe_probe_cluster_created_events[i]);
  }

  auto& parsed_bwe_probe_failure_events = parsed_log.bwe_probe_failure_events();
  ASSERT_EQ(parsed_bwe_probe_failure_events.size(), probe_failure_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_failure_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeFailureEvent(
        *probe_failure_list_[i], parsed_bwe_probe_failure_events[i]);
  }

  auto& parsed_bwe_probe_success_events = parsed_log.bwe_probe_success_events();
  ASSERT_EQ(parsed_bwe_probe_success_events.size(), probe_success_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_success_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeSuccessEvent(
        *probe_success_list_[i], parsed_bwe_probe_success_events[i]);
  }

  auto& parsed_frame_decoded_events = parsed_log.decoded_frames();
  ASSERT_EQ(parsed_frame_decoded_events.size(),
            frame_decoded_event_list_.size());
  for (size_t i = 0; i < parsed_frame_decoded_events.size(); i++) {
    verifier_.VerifyLoggedFrameDecoded(*frame_decoded_event_list_[i],<commit_msg>Add missing tests for DTLS state logging in RTC event log.<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>
#include <limits>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "api/rtc_event_log/rtc_event_log.h"
#include "api/rtc_event_log/rtc_event_log_factory.h"
#include "api/rtc_event_log_output_file.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
#include "logging/rtc_event_log/events/rtc_event_generic_ack_received.h"
#include "logging/rtc_event_log/events/rtc_event_generic_packet_received.h"
#include "logging/rtc_event_log/events/rtc_event_generic_packet_sent.h"
#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h"
#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "logging/rtc_event_log/rtc_event_log_unittest_helper.h"
#include "logging/rtc_event_log/rtc_stream_config.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "rtc_base/checks.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/random.h"
#include "test/gtest.h"
#include "test/testsupport/file_utils.h"

namespace webrtc {

namespace {

struct EventCounts {
  size_t audio_send_streams = 0;
  size_t audio_recv_streams = 0;
  size_t video_send_streams = 0;
  size_t video_recv_streams = 0;
  size_t alr_states = 0;
  size_t route_changes = 0;
  size_t audio_playouts = 0;
  size_t ana_configs = 0;
  size_t bwe_loss_events = 0;
  size_t bwe_delay_events = 0;
  size_t dtls_transport_states = 0;
  size_t dtls_writable_states = 0;
  size_t frame_decoded_events = 0;
  size_t probe_creations = 0;
  size_t probe_successes = 0;
  size_t probe_failures = 0;
  size_t ice_configs = 0;
  size_t ice_events = 0;
  size_t incoming_rtp_packets = 0;
  size_t outgoing_rtp_packets = 0;
  size_t incoming_rtcp_packets = 0;
  size_t outgoing_rtcp_packets = 0;
  size_t generic_packets_sent = 0;
  size_t generic_packets_received = 0;
  size_t generic_acks_received = 0;

  size_t total_nonconfig_events() const {
    return alr_states + route_changes + audio_playouts + ana_configs +
           bwe_loss_events + bwe_delay_events + dtls_transport_states +
           dtls_writable_states + frame_decoded_events + probe_creations +
           probe_successes + probe_failures + ice_configs + ice_events +
           incoming_rtp_packets + outgoing_rtp_packets + incoming_rtcp_packets +
           outgoing_rtcp_packets + generic_packets_sent +
           generic_packets_received + generic_acks_received;
  }

  size_t total_config_events() const {
    return audio_send_streams + audio_recv_streams + video_send_streams +
           video_recv_streams;
  }

  size_t total_events() const {
    return total_nonconfig_events() + total_config_events();
  }
};

class RtcEventLogSession
    : public ::testing::TestWithParam<
          std::tuple<uint64_t, int64_t, RtcEventLog::EncodingType>> {
 public:
  RtcEventLogSession()
      : seed_(std::get<0>(GetParam())),
        prng_(seed_),
        output_period_ms_(std::get<1>(GetParam())),
        encoding_type_(std::get<2>(GetParam())),
        gen_(seed_ * 880001UL),
        verifier_(encoding_type_) {
    clock_.SetTime(Timestamp::Micros(prng_.Rand<uint32_t>()));
    // Find the name of the current test, in order to use it as a temporary
    // filename.
    // TODO(terelius): Use a general utility function to generate a temp file.
    auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
    std::string test_name =
        std::string(test_info->test_case_name()) + "_" + test_info->name();
    std::replace(test_name.begin(), test_name.end(), '/', '_');
    temp_filename_ = test::OutputPath() + test_name;
  }

  // Create and buffer the config events and |num_events_before_log_start|
  // randomized non-config events. Then call StartLogging and finally create and
  // write the remaining non-config events.
  void WriteLog(EventCounts count, size_t num_events_before_log_start);
  void ReadAndVerifyLog();

  bool IsNewFormat() {
    return encoding_type_ == RtcEventLog::EncodingType::NewFormat;
  }

 private:
  void WriteAudioRecvConfigs(size_t audio_recv_streams, RtcEventLog* event_log);
  void WriteAudioSendConfigs(size_t audio_send_streams, RtcEventLog* event_log);
  void WriteVideoRecvConfigs(size_t video_recv_streams, RtcEventLog* event_log);
  void WriteVideoSendConfigs(size_t video_send_streams, RtcEventLog* event_log);

  std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> incoming_extensions_;
  std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> outgoing_extensions_;

  // Config events.
  std::vector<std::unique_ptr<RtcEventAudioSendStreamConfig>>
      audio_send_config_list_;
  std::vector<std::unique_ptr<RtcEventAudioReceiveStreamConfig>>
      audio_recv_config_list_;
  std::vector<std::unique_ptr<RtcEventVideoSendStreamConfig>>
      video_send_config_list_;
  std::vector<std::unique_ptr<RtcEventVideoReceiveStreamConfig>>
      video_recv_config_list_;

  // Regular events.
  std::vector<std::unique_ptr<RtcEventAlrState>> alr_state_list_;
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>>
      audio_playout_map_;  // Groups audio by SSRC.
  std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>>
      ana_configs_list_;
  std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> bwe_delay_list_;
  std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> bwe_loss_list_;
  std::vector<std::unique_ptr<RtcEventDtlsTransportState>>
      dtls_transport_state_list_;
  std::vector<std::unique_ptr<RtcEventDtlsWritableState>>
      dtls_writable_state_list_;
  std::vector<std::unique_ptr<RtcEventFrameDecoded>> frame_decoded_event_list_;
  std::vector<std::unique_ptr<RtcEventGenericAckReceived>>
      generic_acks_received_;
  std::vector<std::unique_ptr<RtcEventGenericPacketReceived>>
      generic_packets_received_;
  std::vector<std::unique_ptr<RtcEventGenericPacketSent>> generic_packets_sent_;
  std::vector<std::unique_ptr<RtcEventIceCandidatePair>> ice_event_list_;
  std::vector<std::unique_ptr<RtcEventIceCandidatePairConfig>> ice_config_list_;
  std::vector<std::unique_ptr<RtcEventProbeClusterCreated>>
      probe_creation_list_;
  std::vector<std::unique_ptr<RtcEventProbeResultFailure>> probe_failure_list_;
  std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_;
  std::vector<std::unique_ptr<RtcEventRouteChange>> route_change_list_;
  std::vector<std::unique_ptr<RtcEventRemoteEstimate>> remote_estimate_list_;
  std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> incoming_rtcp_list_;
  std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> outgoing_rtcp_list_;
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketIncoming>>>
      incoming_rtp_map_;  // Groups incoming RTP by SSRC.
  std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketOutgoing>>>
      outgoing_rtp_map_;  // Groups outgoing RTP by SSRC.

  int64_t start_time_us_;
  int64_t utc_start_time_us_;
  int64_t stop_time_us_;

  int64_t first_timestamp_ms_ = std::numeric_limits<int64_t>::max();
  int64_t last_timestamp_ms_ = std::numeric_limits<int64_t>::min();

  const uint64_t seed_;
  Random prng_;
  const int64_t output_period_ms_;
  const RtcEventLog::EncodingType encoding_type_;
  test::EventGenerator gen_;
  test::EventVerifier verifier_;
  rtc::ScopedFakeClock clock_;
  std::string temp_filename_;
};

bool SsrcUsed(
    uint32_t ssrc,
    const std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>>& streams) {
  for (const auto& kv : streams) {
    if (kv.first == ssrc)
      return true;
  }
  return false;
}

void RtcEventLogSession::WriteAudioRecvConfigs(size_t audio_recv_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  uint32_t ssrc;
  for (size_t i = 0; i < audio_recv_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, incoming_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    incoming_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewAudioReceiveStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    audio_recv_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteAudioSendConfigs(size_t audio_send_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  uint32_t ssrc;
  for (size_t i = 0; i < audio_send_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, outgoing_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    outgoing_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewAudioSendStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    audio_send_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteVideoRecvConfigs(size_t video_recv_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  RTC_CHECK_GE(video_recv_streams, 1);

  // Force least one stream to use all header extensions, to ensure
  // (statistically) that every extension is tested in packet creation.
  RtpHeaderExtensionMap all_extensions =
      ParsedRtcEventLog::GetDefaultHeaderExtensionMap();

  clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
  uint32_t ssrc = prng_.Rand<uint32_t>();
  incoming_extensions_.emplace_back(ssrc, all_extensions);
  auto event = gen_.NewVideoReceiveStreamConfig(ssrc, all_extensions);
  event_log->Log(event->Copy());
  video_recv_config_list_.push_back(std::move(event));
  for (size_t i = 1; i < video_recv_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, incoming_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    incoming_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    video_recv_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteVideoSendConfigs(size_t video_send_streams,
                                               RtcEventLog* event_log) {
  RTC_CHECK(event_log != nullptr);
  RTC_CHECK_GE(video_send_streams, 1);

  // Force least one stream to use all header extensions, to ensure
  // (statistically) that every extension is tested in packet creation.
  RtpHeaderExtensionMap all_extensions =
      ParsedRtcEventLog::GetDefaultHeaderExtensionMap();

  clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
  uint32_t ssrc = prng_.Rand<uint32_t>();
  outgoing_extensions_.emplace_back(ssrc, all_extensions);
  auto event = gen_.NewVideoSendStreamConfig(ssrc, all_extensions);
  event_log->Log(event->Copy());
  video_send_config_list_.push_back(std::move(event));
  for (size_t i = 1; i < video_send_streams; i++) {
    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    do {
      ssrc = prng_.Rand<uint32_t>();
    } while (SsrcUsed(ssrc, outgoing_extensions_));
    RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap();
    outgoing_extensions_.emplace_back(ssrc, extensions);
    auto event = gen_.NewVideoSendStreamConfig(ssrc, extensions);
    event_log->Log(event->Copy());
    video_send_config_list_.push_back(std::move(event));
  }
}

void RtcEventLogSession::WriteLog(EventCounts count,
                                  size_t num_events_before_start) {
  // TODO(terelius): Allow test to run with either a real or a fake clock_.
  // Maybe always use the ScopedFakeClock, but conditionally SleepMs()?

  auto task_queue_factory = CreateDefaultTaskQueueFactory();
  RtcEventLogFactory rtc_event_log_factory(task_queue_factory.get());
  // The log file will be flushed to disk when the event_log goes out of scope.
  std::unique_ptr<RtcEventLog> event_log =
      rtc_event_log_factory.CreateRtcEventLog(encoding_type_);

  // We can't send or receive packets without configured streams.
  RTC_CHECK_GE(count.video_recv_streams, 1);
  RTC_CHECK_GE(count.video_send_streams, 1);

  WriteAudioRecvConfigs(count.audio_recv_streams, event_log.get());
  WriteAudioSendConfigs(count.audio_send_streams, event_log.get());
  WriteVideoRecvConfigs(count.video_recv_streams, event_log.get());
  WriteVideoSendConfigs(count.video_send_streams, event_log.get());

  size_t remaining_events = count.total_nonconfig_events();
  ASSERT_LE(num_events_before_start, remaining_events);
  size_t remaining_events_at_start = remaining_events - num_events_before_start;
  for (; remaining_events > 0; remaining_events--) {
    if (remaining_events == remaining_events_at_start) {
      clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
      event_log->StartLogging(
          std::make_unique<RtcEventLogOutputFile>(temp_filename_, 10000000),
          output_period_ms_);
      start_time_us_ = rtc::TimeMicros();
      utc_start_time_us_ = rtc::TimeUTCMicros();
    }

    clock_.AdvanceTime(TimeDelta::Millis(prng_.Rand(20)));
    size_t selection = prng_.Rand(remaining_events - 1);
    first_timestamp_ms_ = std::min(first_timestamp_ms_, rtc::TimeMillis());
    last_timestamp_ms_ = std::max(last_timestamp_ms_, rtc::TimeMillis());

    if (selection < count.alr_states) {
      auto event = gen_.NewAlrState();
      event_log->Log(event->Copy());
      alr_state_list_.push_back(std::move(event));
      count.alr_states--;
      continue;
    }
    selection -= count.alr_states;

    if (selection < count.route_changes) {
      auto event = gen_.NewRouteChange();
      event_log->Log(event->Copy());
      route_change_list_.push_back(std::move(event));
      count.route_changes--;
      continue;
    }
    selection -= count.route_changes;

    if (selection < count.audio_playouts) {
      size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
      // This might be a video SSRC, but the parser does not use the config.
      uint32_t ssrc = incoming_extensions_[stream].first;
      auto event = gen_.NewAudioPlayout(ssrc);
      event_log->Log(event->Copy());
      audio_playout_map_[ssrc].push_back(std::move(event));
      count.audio_playouts--;
      continue;
    }
    selection -= count.audio_playouts;

    if (selection < count.ana_configs) {
      auto event = gen_.NewAudioNetworkAdaptation();
      event_log->Log(event->Copy());
      ana_configs_list_.push_back(std::move(event));
      count.ana_configs--;
      continue;
    }
    selection -= count.ana_configs;

    if (selection < count.bwe_loss_events) {
      auto event = gen_.NewBweUpdateLossBased();
      event_log->Log(event->Copy());
      bwe_loss_list_.push_back(std::move(event));
      count.bwe_loss_events--;
      continue;
    }
    selection -= count.bwe_loss_events;

    if (selection < count.bwe_delay_events) {
      auto event = gen_.NewBweUpdateDelayBased();
      event_log->Log(event->Copy());
      bwe_delay_list_.push_back(std::move(event));
      count.bwe_delay_events--;
      continue;
    }
    selection -= count.bwe_delay_events;

    if (selection < count.probe_creations) {
      auto event = gen_.NewProbeClusterCreated();
      event_log->Log(event->Copy());
      probe_creation_list_.push_back(std::move(event));
      count.probe_creations--;
      continue;
    }
    selection -= count.probe_creations;

    if (selection < count.probe_successes) {
      auto event = gen_.NewProbeResultSuccess();
      event_log->Log(event->Copy());
      probe_success_list_.push_back(std::move(event));
      count.probe_successes--;
      continue;
    }
    selection -= count.probe_successes;

    if (selection < count.probe_failures) {
      auto event = gen_.NewProbeResultFailure();
      event_log->Log(event->Copy());
      probe_failure_list_.push_back(std::move(event));
      count.probe_failures--;
      continue;
    }
    selection -= count.probe_failures;

    if (selection < count.dtls_transport_states) {
      auto event = gen_.NewDtlsTransportState();
      event_log->Log(event->Copy());
      dtls_transport_state_list_.push_back(std::move(event));
      count.dtls_transport_states--;
      continue;
    }
    selection -= count.dtls_transport_states;

    if (selection < count.dtls_writable_states) {
      auto event = gen_.NewDtlsWritableState();
      event_log->Log(event->Copy());
      dtls_writable_state_list_.push_back(std::move(event));
      count.dtls_writable_states--;
      continue;
    }
    selection -= count.dtls_writable_states;

    if (selection < count.frame_decoded_events) {
      auto event = gen_.NewFrameDecodedEvent();
      event_log->Log(event->Copy());
      frame_decoded_event_list_.push_back(std::move(event));
      count.frame_decoded_events--;
      continue;
    }
    selection -= count.frame_decoded_events;

    if (selection < count.ice_configs) {
      auto event = gen_.NewIceCandidatePairConfig();
      event_log->Log(event->Copy());
      ice_config_list_.push_back(std::move(event));
      count.ice_configs--;
      continue;
    }
    selection -= count.ice_configs;

    if (selection < count.ice_events) {
      auto event = gen_.NewIceCandidatePair();
      event_log->Log(event->Copy());
      ice_event_list_.push_back(std::move(event));
      count.ice_events--;
      continue;
    }
    selection -= count.ice_events;

    if (selection < count.incoming_rtp_packets) {
      size_t stream = prng_.Rand(incoming_extensions_.size() - 1);
      uint32_t ssrc = incoming_extensions_[stream].first;
      auto event =
          gen_.NewRtpPacketIncoming(ssrc, incoming_extensions_[stream].second);
      event_log->Log(event->Copy());
      incoming_rtp_map_[ssrc].push_back(std::move(event));
      count.incoming_rtp_packets--;
      continue;
    }
    selection -= count.incoming_rtp_packets;

    if (selection < count.outgoing_rtp_packets) {
      size_t stream = prng_.Rand(outgoing_extensions_.size() - 1);
      uint32_t ssrc = outgoing_extensions_[stream].first;
      auto event =
          gen_.NewRtpPacketOutgoing(ssrc, outgoing_extensions_[stream].second);
      event_log->Log(event->Copy());
      outgoing_rtp_map_[ssrc].push_back(std::move(event));
      count.outgoing_rtp_packets--;
      continue;
    }
    selection -= count.outgoing_rtp_packets;

    if (selection < count.incoming_rtcp_packets) {
      auto event = gen_.NewRtcpPacketIncoming();
      event_log->Log(event->Copy());
      incoming_rtcp_list_.push_back(std::move(event));
      count.incoming_rtcp_packets--;
      continue;
    }
    selection -= count.incoming_rtcp_packets;

    if (selection < count.outgoing_rtcp_packets) {
      auto event = gen_.NewRtcpPacketOutgoing();
      event_log->Log(event->Copy());
      outgoing_rtcp_list_.push_back(std::move(event));
      count.outgoing_rtcp_packets--;
      continue;
    }
    selection -= count.outgoing_rtcp_packets;

    if (selection < count.generic_packets_sent) {
      auto event = gen_.NewGenericPacketSent();
      generic_packets_sent_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_packets_sent--;
      continue;
    }
    selection -= count.generic_packets_sent;

    if (selection < count.generic_packets_received) {
      auto event = gen_.NewGenericPacketReceived();
      generic_packets_received_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_packets_received--;
      continue;
    }
    selection -= count.generic_packets_received;

    if (selection < count.generic_acks_received) {
      auto event = gen_.NewGenericAckReceived();
      generic_acks_received_.push_back(event->Copy());
      event_log->Log(std::move(event));
      count.generic_acks_received--;
      continue;
    }
    selection -= count.generic_acks_received;

    RTC_NOTREACHED();
  }

  event_log->StopLogging();
  stop_time_us_ = rtc::TimeMicros();

  ASSERT_EQ(count.total_nonconfig_events(), static_cast<size_t>(0));
}

// Read the file and verify that what we read back from the event log is the
// same as what we wrote down.
void RtcEventLogSession::ReadAndVerifyLog() {
  // Read the generated file from disk.
  ParsedRtcEventLog parsed_log;
  ASSERT_TRUE(parsed_log.ParseFile(temp_filename_).ok());

  // Start and stop events.
  auto& parsed_start_log_events = parsed_log.start_log_events();
  ASSERT_EQ(parsed_start_log_events.size(), static_cast<size_t>(1));
  verifier_.VerifyLoggedStartEvent(start_time_us_, utc_start_time_us_,
                                   parsed_start_log_events[0]);

  auto& parsed_stop_log_events = parsed_log.stop_log_events();
  ASSERT_EQ(parsed_stop_log_events.size(), static_cast<size_t>(1));
  verifier_.VerifyLoggedStopEvent(stop_time_us_, parsed_stop_log_events[0]);

  auto& parsed_alr_state_events = parsed_log.alr_state_events();
  ASSERT_EQ(parsed_alr_state_events.size(), alr_state_list_.size());
  for (size_t i = 0; i < parsed_alr_state_events.size(); i++) {
    verifier_.VerifyLoggedAlrStateEvent(*alr_state_list_[i],
                                        parsed_alr_state_events[i]);
  }
  auto& parsed_route_change_events = parsed_log.route_change_events();
  ASSERT_EQ(parsed_route_change_events.size(), route_change_list_.size());
  for (size_t i = 0; i < parsed_route_change_events.size(); i++) {
    verifier_.VerifyLoggedRouteChangeEvent(*route_change_list_[i],
                                           parsed_route_change_events[i]);
  }

  const auto& parsed_audio_playout_map = parsed_log.audio_playout_events();
  ASSERT_EQ(parsed_audio_playout_map.size(), audio_playout_map_.size());
  for (const auto& kv : parsed_audio_playout_map) {
    uint32_t ssrc = kv.first;
    const auto& parsed_audio_playout_stream = kv.second;
    const auto& audio_playout_stream = audio_playout_map_[ssrc];
    ASSERT_EQ(parsed_audio_playout_stream.size(), audio_playout_stream.size());
    for (size_t i = 0; i < parsed_audio_playout_map.size(); i++) {
      verifier_.VerifyLoggedAudioPlayoutEvent(*audio_playout_stream[i],
                                              parsed_audio_playout_stream[i]);
    }
  }

  auto& parsed_audio_network_adaptation_events =
      parsed_log.audio_network_adaptation_events();
  ASSERT_EQ(parsed_audio_network_adaptation_events.size(),
            ana_configs_list_.size());
  for (size_t i = 0; i < parsed_audio_network_adaptation_events.size(); i++) {
    verifier_.VerifyLoggedAudioNetworkAdaptationEvent(
        *ana_configs_list_[i], parsed_audio_network_adaptation_events[i]);
  }

  auto& parsed_bwe_delay_updates = parsed_log.bwe_delay_updates();
  ASSERT_EQ(parsed_bwe_delay_updates.size(), bwe_delay_list_.size());
  for (size_t i = 0; i < parsed_bwe_delay_updates.size(); i++) {
    verifier_.VerifyLoggedBweDelayBasedUpdate(*bwe_delay_list_[i],
                                              parsed_bwe_delay_updates[i]);
  }

  auto& parsed_bwe_loss_updates = parsed_log.bwe_loss_updates();
  ASSERT_EQ(parsed_bwe_loss_updates.size(), bwe_loss_list_.size());
  for (size_t i = 0; i < parsed_bwe_loss_updates.size(); i++) {
    verifier_.VerifyLoggedBweLossBasedUpdate(*bwe_loss_list_[i],
                                             parsed_bwe_loss_updates[i]);
  }

  auto& parsed_bwe_probe_cluster_created_events =
      parsed_log.bwe_probe_cluster_created_events();
  ASSERT_EQ(parsed_bwe_probe_cluster_created_events.size(),
            probe_creation_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_cluster_created_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeClusterCreatedEvent(
        *probe_creation_list_[i], parsed_bwe_probe_cluster_created_events[i]);
  }

  auto& parsed_bwe_probe_failure_events = parsed_log.bwe_probe_failure_events();
  ASSERT_EQ(parsed_bwe_probe_failure_events.size(), probe_failure_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_failure_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeFailureEvent(
        *probe_failure_list_[i], parsed_bwe_probe_failure_events[i]);
  }

  auto& parsed_bwe_probe_success_events = parsed_log.bwe_probe_success_events();
  ASSERT_EQ(parsed_bwe_probe_success_events.size(), probe_success_list_.size());
  for (size_t i = 0; i < parsed_bwe_probe_success_events.size(); i++) {
    verifier_.VerifyLoggedBweProbeSuccessEvent(
        *probe_success_list_[i], parsed_bwe_probe_success_events[i]);
  }

  auto& parsed_dtls_transport_states = parsed_log.dtls_transport_states();
  ASSERT_EQ(parsed_dtls_transport_states.size(),
            dtls_transport_state_list_.size());
  for (size_t i = 0; i < parsed_dtls_transport_states.size(); i++) {
    verifier_.VerifyLoggedDtlsTransportState(*dtls_transport_state_list_[i],
                                             parsed_dtls_transport_states[i]);
  }

  auto& parsed_dtls_writable_states = parsed_log.dtls_writable_states();
  ASSERT_EQ(parsed_dtls_writable_states.size(),
            dtls_writable_state_list_.size());
  for (size_t i = 0; i < parsed_dtls_writable_states.size(); i++) {
    verifier_.VerifyLoggedDtlsWritableState(*dtls_writable_state_list_[i],
                                            parsed_dtls_writable_states[i]);
  }

  auto& parsed_frame_decoded_events = parsed_log.decoded_frames();
  ASSERT_EQ(parsed_frame_decoded_events.size(),
            frame_decoded_event_list_.size());
  for (size_t i = 0; i < parsed_frame_decoded_events.size(); i++) {
    verifier_.VerifyLoggedFrameDecoded(*frame_decoded_event_list_[i],
{'fraction_non_alphanumeric': 0.10981724983285046, 'fraction_numerical': 0.005831661837902087, 'mean_word_length': 4.45045045045045, 'pattern_counts': {'":': 0, '<': 251, '<?xml version=': 0, '>': 299, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4035029', 'n_tokens_mistral': 18231, 'n_tokens_neox': 17809, 'n_words': 2705}