chromium/components/tracing/common/etw_system_data_source_win_unittest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/tracing/common/etw_system_data_source_win.h"

#include <vector>

#include "base/containers/span.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h"
#include "third_party/perfetto/protos/perfetto/trace/etw/etw.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/etw/etw_event.pbzero.h"

namespace tracing {

TEST(EtwSystemDataSource, DecodeCSwitchEvent_Empty) {
  std::vector<uint8_t> data = {};
  protozero::HeapBuffered<perfetto::protos::pbzero::EtwTraceEvent> event;
  EXPECT_FALSE(
      EtwSystemDataSource::DecodeCSwitchEvent({data.data(), 0U}, *event.get()));
}

TEST(EtwSystemDataSource, DecodeCSwitchEvent_TooShort) {
  std::vector<uint8_t> data(0x00, 23);
  protozero::HeapBuffered<perfetto::protos::pbzero::EtwTraceEvent> event;
  EXPECT_FALSE(EtwSystemDataSource::DecodeCSwitchEvent(
      {data.data(), data.size()}, *event.get()));
}

TEST(EtwSystemDataSource, DecodeCSwitchEvent) {
  std::vector<uint8_t> data = {
      0x55, 0x00, 0x00, 0x00,  // new_thread_id
      0x44, 0x00, 0x00, 0x00,  // old_thread_id
      0x01,                    // new_thread_priority
      0x02,                    // old_thread_priority
      0x03,                    // previous_c_state
      0x42,                    // SpareByte
      36,                      // old_thread_wait_reason = WR_RUNDOWN
      1,                       // old_thread_wait_mode = USER_MODE
      7,                       // old_thread_state = DEFERRED_READY
      0x04,                    // old_thread_wait_ideal_processor
      0x05, 0x00, 0x00, 0x00,  // new_thread_wait_time
      0x42, 0x42, 0x42, 0x42,  // Reserved
  };
  protozero::HeapBuffered<perfetto::protos::pbzero::EtwTraceEvent> event;
  ASSERT_TRUE(EtwSystemDataSource::DecodeCSwitchEvent(
      {data.data(), data.size()}, *event.get()));

  auto serialized = event.SerializeAsString();
  perfetto::protos::pbzero::EtwTraceEvent::Decoder decoded_event(serialized);

  ASSERT_TRUE(decoded_event.has_c_switch());
  perfetto::protos::pbzero::CSwitchEtwEvent::Decoder c_switch(
      decoded_event.c_switch());
  EXPECT_EQ(0x55u, c_switch.new_thread_id());
  EXPECT_EQ(0x44u, c_switch.old_thread_id());
  EXPECT_EQ(0x01, c_switch.new_thread_priority());
  EXPECT_EQ(0x02, c_switch.old_thread_priority());
  EXPECT_EQ(0x03u, c_switch.previous_c_state());
  EXPECT_EQ(perfetto::protos::pbzero::CSwitchEtwEvent::WR_RUNDOWN,
            c_switch.old_thread_wait_reason());
  EXPECT_EQ(perfetto::protos::pbzero::CSwitchEtwEvent::USER_MODE,
            c_switch.old_thread_wait_mode());
  EXPECT_EQ(perfetto::protos::pbzero::CSwitchEtwEvent::DEFERRED_READY,
            c_switch.old_thread_state());
  EXPECT_EQ(0x04, c_switch.old_thread_wait_ideal_processor());
  EXPECT_EQ(0x05u, c_switch.new_thread_wait_time());
}

}  // namespace tracing