Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <inttypes.h>
     18 #include <unistd.h>
     19 
     20 #include "gmock/gmock.h"
     21 #include "gtest/gtest.h"
     22 #include "perfetto/base/temp_file.h"
     23 #include "perfetto/tracing/core/consumer.h"
     24 #include "perfetto/tracing/core/data_source_config.h"
     25 #include "perfetto/tracing/core/data_source_descriptor.h"
     26 #include "perfetto/tracing/core/producer.h"
     27 #include "perfetto/tracing/core/trace_config.h"
     28 #include "perfetto/tracing/core/trace_packet.h"
     29 #include "perfetto/tracing/core/trace_writer.h"
     30 #include "perfetto/tracing/ipc/consumer_ipc_client.h"
     31 #include "perfetto/tracing/ipc/producer_ipc_client.h"
     32 #include "perfetto/tracing/ipc/service_ipc_host.h"
     33 #include "src/base/test/test_task_runner.h"
     34 #include "src/ipc/test/test_socket.h"
     35 
     36 #include "perfetto/config/trace_config.pb.h"
     37 #include "perfetto/trace/test_event.pbzero.h"
     38 #include "perfetto/trace/trace.pb.h"
     39 #include "perfetto/trace/trace_packet.pb.h"
     40 #include "perfetto/trace/trace_packet.pbzero.h"
     41 
     42 namespace perfetto {
     43 namespace {
     44 
     45 using testing::Invoke;
     46 using testing::InvokeWithoutArgs;
     47 using testing::_;
     48 
     49 constexpr char kProducerSockName[] = TEST_SOCK_NAME("tracing_test-producer");
     50 constexpr char kConsumerSockName[] = TEST_SOCK_NAME("tracing_test-consumer");
     51 
     52 class MockProducer : public Producer {
     53  public:
     54   ~MockProducer() override {}
     55 
     56   // Producer implementation.
     57   MOCK_METHOD0(OnConnect, void());
     58   MOCK_METHOD0(OnDisconnect, void());
     59   MOCK_METHOD2(CreateDataSourceInstance,
     60                void(DataSourceInstanceID, const DataSourceConfig&));
     61   MOCK_METHOD1(TearDownDataSourceInstance, void(DataSourceInstanceID));
     62   MOCK_METHOD0(uid, uid_t());
     63   MOCK_METHOD0(OnTracingSetup, void());
     64   MOCK_METHOD3(Flush,
     65                void(FlushRequestID, const DataSourceInstanceID*, size_t));
     66 };
     67 
     68 class MockConsumer : public Consumer {
     69  public:
     70   ~MockConsumer() override {}
     71 
     72   // Producer implementation.
     73   MOCK_METHOD0(OnConnect, void());
     74   MOCK_METHOD0(OnDisconnect, void());
     75   MOCK_METHOD0(OnTracingDisabled, void());
     76   MOCK_METHOD2(OnTracePackets, void(std::vector<TracePacket>*, bool));
     77 
     78   // Workaround, gmock doesn't support yet move-only types, passing a pointer.
     79   void OnTraceData(std::vector<TracePacket> packets, bool has_more) {
     80     OnTracePackets(&packets, has_more);
     81   }
     82 };
     83 
     84 void CheckTraceStats(const protos::TracePacket& packet) {
     85   EXPECT_TRUE(packet.has_trace_stats());
     86   EXPECT_GE(packet.trace_stats().producers_seen(), 1);
     87   EXPECT_EQ(1, packet.trace_stats().producers_connected());
     88   EXPECT_EQ(1, packet.trace_stats().data_sources_registered());
     89   EXPECT_EQ(1, packet.trace_stats().tracing_sessions());
     90   EXPECT_EQ(1, packet.trace_stats().total_buffers());
     91   EXPECT_EQ(1, packet.trace_stats().buffer_stats_size());
     92 
     93   const auto& buf_stats = packet.trace_stats().buffer_stats(0);
     94   EXPECT_GT(buf_stats.bytes_written(), 0);
     95   EXPECT_GT(buf_stats.chunks_written(), 0);
     96   EXPECT_EQ(0, buf_stats.chunks_overwritten());
     97   EXPECT_EQ(0, buf_stats.write_wrap_count());
     98   EXPECT_EQ(0, buf_stats.patches_failed());
     99   EXPECT_EQ(0, buf_stats.readaheads_failed());
    100   EXPECT_EQ(0, buf_stats.abi_violations());
    101 }
    102 
    103 class TracingIntegrationTest : public ::testing::Test {
    104  public:
    105   void SetUp() override {
    106     DESTROY_TEST_SOCK(kProducerSockName);
    107     DESTROY_TEST_SOCK(kConsumerSockName);
    108     task_runner_.reset(new base::TestTaskRunner());
    109 
    110     // Create the service host.
    111     svc_ = ServiceIPCHost::CreateInstance(task_runner_.get());
    112     svc_->Start(kProducerSockName, kConsumerSockName);
    113 
    114     // Create and connect a Producer.
    115     producer_endpoint_ = ProducerIPCClient::Connect(
    116         kProducerSockName, &producer_, "perfetto.mock_producer",
    117         task_runner_.get());
    118     auto on_producer_connect =
    119         task_runner_->CreateCheckpoint("on_producer_connect");
    120     EXPECT_CALL(producer_, OnConnect()).WillOnce(Invoke(on_producer_connect));
    121     task_runner_->RunUntilCheckpoint("on_producer_connect");
    122 
    123     // Register a data source.
    124     DataSourceDescriptor ds_desc;
    125     ds_desc.set_name("perfetto.test");
    126     producer_endpoint_->RegisterDataSource(ds_desc);
    127 
    128     // Create and connect a Consumer.
    129     consumer_endpoint_ = ConsumerIPCClient::Connect(
    130         kConsumerSockName, &consumer_, task_runner_.get());
    131     auto on_consumer_connect =
    132         task_runner_->CreateCheckpoint("on_consumer_connect");
    133     EXPECT_CALL(consumer_, OnConnect()).WillOnce(Invoke(on_consumer_connect));
    134     task_runner_->RunUntilCheckpoint("on_consumer_connect");
    135 
    136     ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&producer_));
    137     ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&consumer_));
    138   }
    139 
    140   void TearDown() override {
    141     // Destroy the service and check that both Producer and Consumer see an
    142     // OnDisconnect() call.
    143 
    144     auto on_producer_disconnect =
    145         task_runner_->CreateCheckpoint("on_producer_disconnect");
    146     EXPECT_CALL(producer_, OnDisconnect())
    147         .WillOnce(Invoke(on_producer_disconnect));
    148 
    149     auto on_consumer_disconnect =
    150         task_runner_->CreateCheckpoint("on_consumer_disconnect");
    151     EXPECT_CALL(consumer_, OnDisconnect())
    152         .WillOnce(Invoke(on_consumer_disconnect));
    153 
    154     svc_.reset();
    155     task_runner_->RunUntilCheckpoint("on_producer_disconnect");
    156     task_runner_->RunUntilCheckpoint("on_consumer_disconnect");
    157 
    158     ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&producer_));
    159     ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&consumer_));
    160 
    161     task_runner_.reset();
    162     DESTROY_TEST_SOCK(kProducerSockName);
    163     DESTROY_TEST_SOCK(kConsumerSockName);
    164   }
    165 
    166   std::unique_ptr<base::TestTaskRunner> task_runner_;
    167   std::unique_ptr<ServiceIPCHost> svc_;
    168   std::unique_ptr<Service::ProducerEndpoint> producer_endpoint_;
    169   MockProducer producer_;
    170   std::unique_ptr<Service::ConsumerEndpoint> consumer_endpoint_;
    171   MockConsumer consumer_;
    172 };
    173 
    174 TEST_F(TracingIntegrationTest, WithIPCTransport) {
    175   // Start tracing.
    176   TraceConfig trace_config;
    177   trace_config.add_buffers()->set_size_kb(4096 * 10);
    178   auto* ds_config = trace_config.add_data_sources()->mutable_config();
    179   ds_config->set_name("perfetto.test");
    180   ds_config->set_target_buffer(0);
    181   consumer_endpoint_->EnableTracing(trace_config);
    182 
    183   // At this point, the Producer should be asked to turn its data source on.
    184   DataSourceInstanceID ds_iid = 0;
    185 
    186   BufferID global_buf_id = 0;
    187   auto on_create_ds_instance =
    188       task_runner_->CreateCheckpoint("on_create_ds_instance");
    189   EXPECT_CALL(producer_, OnTracingSetup());
    190   EXPECT_CALL(producer_, CreateDataSourceInstance(_, _))
    191       .WillOnce(
    192           Invoke([on_create_ds_instance, &ds_iid, &global_buf_id](
    193                      DataSourceInstanceID id, const DataSourceConfig& cfg) {
    194             ASSERT_NE(0u, id);
    195             ds_iid = id;
    196             ASSERT_EQ("perfetto.test", cfg.name());
    197             global_buf_id = static_cast<BufferID>(cfg.target_buffer());
    198             ASSERT_NE(0u, global_buf_id);
    199             ASSERT_LE(global_buf_id, std::numeric_limits<BufferID>::max());
    200             on_create_ds_instance();
    201           }));
    202   task_runner_->RunUntilCheckpoint("on_create_ds_instance");
    203 
    204   // Now let the data source fill some pages within the same task.
    205   // Doing so should accumulate a bunch of chunks that will be notified by the
    206   // a future task in one batch.
    207   std::unique_ptr<TraceWriter> writer =
    208       producer_endpoint_->CreateTraceWriter(global_buf_id);
    209   ASSERT_TRUE(writer);
    210 
    211   const size_t kNumPackets = 10;
    212   for (size_t i = 0; i < kNumPackets; i++) {
    213     char buf[16];
    214     sprintf(buf, "evt_%zu", i);
    215     writer->NewTracePacket()->set_for_testing()->set_str(buf, strlen(buf));
    216   }
    217 
    218   // Allow the service to see the CommitData() before reading back.
    219   auto on_data_committed = task_runner_->CreateCheckpoint("on_data_committed");
    220   writer->Flush(on_data_committed);
    221   task_runner_->RunUntilCheckpoint("on_data_committed");
    222 
    223   // Read the log buffer.
    224   consumer_endpoint_->ReadBuffers();
    225   size_t num_pack_rx = 0;
    226   bool saw_clock_snapshot = false;
    227   bool saw_trace_config = false;
    228   bool saw_trace_stats = false;
    229   auto all_packets_rx = task_runner_->CreateCheckpoint("all_packets_rx");
    230   EXPECT_CALL(consumer_, OnTracePackets(_, _))
    231       .WillRepeatedly(
    232           Invoke([&num_pack_rx, all_packets_rx, &trace_config,
    233                   &saw_clock_snapshot, &saw_trace_config, &saw_trace_stats](
    234                      std::vector<TracePacket>* packets, bool has_more) {
    235 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
    236             const int kExpectedMinNumberOfClocks = 1;
    237 #else
    238             const int kExpectedMinNumberOfClocks = 6;
    239 #endif
    240 
    241             for (auto& encoded_packet : *packets) {
    242               protos::TracePacket packet;
    243               ASSERT_TRUE(encoded_packet.Decode(&packet));
    244               if (packet.has_for_testing()) {
    245                 char buf[8];
    246                 sprintf(buf, "evt_%zu", num_pack_rx++);
    247                 EXPECT_EQ(std::string(buf), packet.for_testing().str());
    248               } else if (packet.has_clock_snapshot()) {
    249                 EXPECT_GE(packet.clock_snapshot().clocks_size(),
    250                           kExpectedMinNumberOfClocks);
    251                 saw_clock_snapshot = true;
    252               } else if (packet.has_trace_config()) {
    253                 protos::TraceConfig config_proto;
    254                 trace_config.ToProto(&config_proto);
    255                 Slice expected_slice = Slice::Allocate(
    256                     static_cast<size_t>(config_proto.ByteSize()));
    257                 config_proto.SerializeWithCachedSizesToArray(
    258                     expected_slice.own_data());
    259                 Slice actual_slice = Slice::Allocate(
    260                     static_cast<size_t>(packet.trace_config().ByteSize()));
    261                 packet.trace_config().SerializeWithCachedSizesToArray(
    262                     actual_slice.own_data());
    263                 EXPECT_EQ(std::string(reinterpret_cast<const char*>(
    264                                           expected_slice.own_data()),
    265                                       expected_slice.size),
    266                           std::string(reinterpret_cast<const char*>(
    267                                           actual_slice.own_data()),
    268                                       actual_slice.size));
    269                 saw_trace_config = true;
    270               } else if (packet.has_trace_stats()) {
    271                 saw_trace_stats = true;
    272                 CheckTraceStats(packet);
    273               }
    274             }
    275             if (!has_more)
    276               all_packets_rx();
    277           }));
    278   task_runner_->RunUntilCheckpoint("all_packets_rx");
    279   ASSERT_EQ(kNumPackets, num_pack_rx);
    280   EXPECT_TRUE(saw_clock_snapshot);
    281   EXPECT_TRUE(saw_trace_config);
    282   EXPECT_TRUE(saw_trace_stats);
    283 
    284   // Disable tracing.
    285   consumer_endpoint_->DisableTracing();
    286 
    287   auto on_tracing_disabled =
    288       task_runner_->CreateCheckpoint("on_tracing_disabled");
    289   EXPECT_CALL(producer_, TearDownDataSourceInstance(_));
    290   EXPECT_CALL(consumer_, OnTracingDisabled())
    291       .WillOnce(Invoke(on_tracing_disabled));
    292   task_runner_->RunUntilCheckpoint("on_tracing_disabled");
    293 }
    294 
    295 TEST_F(TracingIntegrationTest, WriteIntoFile) {
    296   // Start tracing.
    297   TraceConfig trace_config;
    298   trace_config.add_buffers()->set_size_kb(4096 * 10);
    299   auto* ds_config = trace_config.add_data_sources()->mutable_config();
    300   ds_config->set_name("perfetto.test");
    301   ds_config->set_target_buffer(0);
    302   trace_config.set_write_into_file(true);
    303   base::TempFile tmp_file = base::TempFile::CreateUnlinked();
    304   consumer_endpoint_->EnableTracing(trace_config,
    305                                     base::ScopedFile(dup(tmp_file.fd())));
    306 
    307   // At this point, the producer_ should be asked to turn its data source on.
    308   BufferID global_buf_id = 0;
    309   auto on_create_ds_instance =
    310       task_runner_->CreateCheckpoint("on_create_ds_instance");
    311   EXPECT_CALL(producer_, OnTracingSetup());
    312   EXPECT_CALL(producer_, CreateDataSourceInstance(_, _))
    313       .WillOnce(Invoke([on_create_ds_instance, &global_buf_id](
    314                            DataSourceInstanceID, const DataSourceConfig& cfg) {
    315         global_buf_id = static_cast<BufferID>(cfg.target_buffer());
    316         on_create_ds_instance();
    317       }));
    318   task_runner_->RunUntilCheckpoint("on_create_ds_instance");
    319 
    320   std::unique_ptr<TraceWriter> writer =
    321       producer_endpoint_->CreateTraceWriter(global_buf_id);
    322   ASSERT_TRUE(writer);
    323 
    324   const size_t kNumPackets = 10;
    325   for (size_t i = 0; i < kNumPackets; i++) {
    326     char buf[16];
    327     sprintf(buf, "evt_%zu", i);
    328     writer->NewTracePacket()->set_for_testing()->set_str(buf, strlen(buf));
    329   }
    330   auto on_data_committed = task_runner_->CreateCheckpoint("on_data_committed");
    331   writer->Flush(on_data_committed);
    332   task_runner_->RunUntilCheckpoint("on_data_committed");
    333 
    334   // Will disable tracing and will force the buffers to be written into the
    335   // file before destroying them.
    336   consumer_endpoint_->FreeBuffers();
    337 
    338   auto on_tracing_disabled =
    339       task_runner_->CreateCheckpoint("on_tracing_disabled");
    340   EXPECT_CALL(producer_, TearDownDataSourceInstance(_));
    341   EXPECT_CALL(consumer_, OnTracingDisabled())
    342       .WillOnce(Invoke(on_tracing_disabled));
    343   task_runner_->RunUntilCheckpoint("on_tracing_disabled");
    344 
    345   // Check that |tmp_file| contains a valid trace.proto message.
    346   ASSERT_EQ(0, lseek(tmp_file.fd(), 0, SEEK_SET));
    347   char tmp_buf[1024];
    348   ssize_t rsize = read(tmp_file.fd(), tmp_buf, sizeof(tmp_buf));
    349   ASSERT_GT(rsize, 0);
    350   protos::Trace tmp_trace;
    351   ASSERT_TRUE(tmp_trace.ParseFromArray(tmp_buf, static_cast<int>(rsize)));
    352   size_t num_test_packet = 0;
    353   bool saw_trace_stats = false;
    354   for (int i = 0; i < tmp_trace.packet_size(); i++) {
    355     const protos::TracePacket& packet = tmp_trace.packet(i);
    356     if (packet.has_for_testing()) {
    357       ASSERT_EQ("evt_" + std::to_string(num_test_packet++),
    358                 packet.for_testing().str());
    359     } else if (packet.has_trace_stats()) {
    360       saw_trace_stats = true;
    361       CheckTraceStats(packet);
    362     }
    363   }
    364   ASSERT_TRUE(saw_trace_stats);
    365 }
    366 
    367 // TODO(primiano): add tests to cover:
    368 // - unknown fields preserved end-to-end.
    369 // - >1 data source.
    370 // - >1 data consumer sharing the same data source, with different TraceBuffers.
    371 // - >1 consumer with > 1 buffer each.
    372 // - Consumer disconnecting in the middle of a ReadBuffers() call.
    373 // - Multiple calls to DisableTracing.
    374 // - Out of order Enable/Disable/FreeBuffers calls.
    375 // - DisableTracing does actually freeze the buffers.
    376 
    377 }  // namespace
    378 }  // namespace perfetto
    379