| /* | |
| * Copyright (c) 2023 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 "logging/rtc_event_log/dependency_descriptor_encoder_decoder.h" | |
| #include <cstdint> | |
| #include <string> | |
| #include <vector> | |
| #include "logging/rtc_event_log/encoder/delta_encoding.h" | |
| #include "logging/rtc_event_log/encoder/optional_blob_encoding.h" | |
| #include "logging/rtc_event_log/rtc_event_log2_proto_include.h" // IWYU pragma: keep | |
| #include "rtc_base/checks.h" | |
| #include "test/gmock.h" | |
| #include "test/gtest.h" | |
| using ::testing::ElementsAre; | |
| using ::testing::Eq; | |
| using ::testing::IsEmpty; | |
| namespace webrtc { | |
| namespace { | |
| constexpr uint64_t kNone = 0; | |
| constexpr uint64_t kEnd = 1; | |
| constexpr uint64_t kBegin = 2; | |
| constexpr uint64_t kBeginEnd = 3; | |
| class DdBuilder { | |
| public: | |
| DdBuilder() : raw_dd(3) {} | |
| DdBuilder& B() { | |
| raw_dd[0] |= 1 << 7; | |
| return *this; | |
| } | |
| DdBuilder& E() { | |
| raw_dd[0] |= 1 << 6; | |
| return *this; | |
| } | |
| DdBuilder& Tid(uint8_t id) { | |
| RTC_DCHECK_LE(id, 0x3F); | |
| raw_dd[0] |= id; | |
| return *this; | |
| } | |
| DdBuilder& Fid(uint16_t id) { | |
| raw_dd[1] = id >> 8; | |
| raw_dd[2] = id; | |
| return *this; | |
| } | |
| DdBuilder& Ext(const std::string& ext) { | |
| raw_dd.insert(raw_dd.end(), ext.begin(), ext.end()); | |
| return *this; | |
| } | |
| std::vector<uint8_t> Build() { return raw_dd; } | |
| private: | |
| std::vector<uint8_t> raw_dd; | |
| }; | |
| TEST(RtcEventLogDependencyDescriptorEncoding, SinglePacket) { | |
| auto encoded = RtcEventLogDependencyDescriptorEncoderDecoder::Encode( | |
| {DdBuilder().B().E().Tid(12).Fid(345).Ext("abc").Build()}); | |
| EXPECT_THAT(encoded->start_end_bit(), Eq(kBeginEnd)); | |
| EXPECT_THAT(encoded->template_id(), Eq(12u)); | |
| EXPECT_THAT(encoded->frame_id(), Eq(345u)); | |
| EXPECT_THAT(encoded->extended_infos(), Eq(EncodeOptionalBlobs({{"abc"}}))); | |
| EXPECT_THAT(encoded->has_start_end_bit_deltas(), Eq(false)); | |
| EXPECT_THAT(encoded->has_template_id_deltas(), Eq(false)); | |
| EXPECT_THAT(encoded->has_frame_id_deltas(), Eq(false)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorEncoding, MultiplePackets) { | |
| auto encoded = RtcEventLogDependencyDescriptorEncoderDecoder::Encode( | |
| {DdBuilder().B().E().Tid(1).Fid(1).Ext("abc").Build(), | |
| DdBuilder().B().Tid(2).Fid(3).Ext("def").Build(), | |
| DdBuilder().E().Tid(2).Fid(3).Build()}); | |
| EXPECT_THAT(encoded->start_end_bit(), Eq(kBeginEnd)); | |
| EXPECT_THAT(encoded->template_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->frame_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->extended_infos(), | |
| Eq(EncodeOptionalBlobs({{"abc"}, {"def"}, {}}))); | |
| EXPECT_THAT(encoded->start_end_bit_deltas(), | |
| Eq(EncodeDeltas({kBeginEnd}, {{kBegin}, {kEnd}}))); | |
| EXPECT_THAT(encoded->template_id_deltas(), Eq(EncodeDeltas({1}, {{2}, {2}}))); | |
| EXPECT_THAT(encoded->frame_id_deltas(), Eq(EncodeDeltas({1}, {{3}, {3}}))); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorEncoding, MultiplePacketsOneFrame) { | |
| auto encoded = RtcEventLogDependencyDescriptorEncoderDecoder::Encode( | |
| {DdBuilder().B().Tid(1).Fid(1).Ext("abc").Build(), | |
| DdBuilder().Tid(1).Fid(1).Build(), | |
| DdBuilder().E().Tid(1).Fid(1).Build()}); | |
| EXPECT_THAT(encoded->start_end_bit(), Eq(kBegin)); | |
| EXPECT_THAT(encoded->template_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->frame_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->extended_infos(), | |
| Eq(EncodeOptionalBlobs({{"abc"}, {}, {}}))); | |
| EXPECT_THAT(encoded->start_end_bit_deltas(), | |
| Eq(EncodeDeltas({kBegin}, {{kNone}, {kEnd}}))); | |
| EXPECT_THAT(encoded->has_template_id_deltas(), Eq(false)); | |
| EXPECT_THAT(encoded->has_frame_id_deltas(), Eq(false)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorEncoding, FirstPacketMissingDd) { | |
| auto encoded = RtcEventLogDependencyDescriptorEncoderDecoder::Encode( | |
| {{}, | |
| DdBuilder().B().E().Tid(1).Fid(1).Build(), | |
| DdBuilder().E().Tid(2).Fid(3).Ext("three!").Build()}); | |
| EXPECT_THAT(encoded->has_start_end_bit(), Eq(false)); | |
| EXPECT_THAT(encoded->has_template_id(), Eq(false)); | |
| EXPECT_THAT(encoded->has_frame_id(), Eq(false)); | |
| EXPECT_THAT(encoded->extended_infos(), | |
| Eq(EncodeOptionalBlobs({{}, {}, {"three!"}}))); | |
| EXPECT_THAT(encoded->start_end_bit_deltas(), | |
| Eq(EncodeDeltas({}, {{kBeginEnd}, {kEnd}}))); | |
| EXPECT_THAT(encoded->template_id_deltas(), Eq(EncodeDeltas({}, {{1}, {2}}))); | |
| EXPECT_THAT(encoded->frame_id_deltas(), Eq(EncodeDeltas({}, {{1}, {3}}))); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorEncoding, SomePacketMissingDd) { | |
| auto encoded = RtcEventLogDependencyDescriptorEncoderDecoder::Encode( | |
| {DdBuilder().B().E().Tid(1).Fid(1).Build(), | |
| {}, | |
| DdBuilder().E().Tid(2).Fid(3).Build()}); | |
| EXPECT_THAT(encoded->start_end_bit(), Eq(kBeginEnd)); | |
| EXPECT_THAT(encoded->template_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->frame_id(), Eq(1u)); | |
| EXPECT_THAT(encoded->extended_infos(), Eq(EncodeOptionalBlobs({{}, {}, {}}))); | |
| EXPECT_THAT(encoded->start_end_bit_deltas(), | |
| Eq(EncodeDeltas({kBeginEnd}, {{}, {kEnd}}))); | |
| EXPECT_THAT(encoded->template_id_deltas(), Eq(EncodeDeltas({1}, {{}, {2}}))); | |
| EXPECT_THAT(encoded->frame_id_deltas(), Eq(EncodeDeltas({1}, {{}, {3}}))); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, SinglePacket) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit(kBeginEnd); | |
| encoded.set_template_id(1); | |
| encoded.set_frame_id(2); | |
| encoded.set_extended_infos(EncodeOptionalBlobs({"abc"})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 1); | |
| auto expected = DdBuilder().B().E().Tid(1).Fid(2).Ext("abc").Build(); | |
| ASSERT_THAT(decoded.ok(), Eq(true)); | |
| EXPECT_THAT(decoded.value(), ElementsAre(expected)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, MultiplePackets) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit(kBeginEnd); | |
| encoded.set_template_id(1); | |
| encoded.set_frame_id(1); | |
| encoded.set_extended_infos(EncodeOptionalBlobs({{"abc"}, {"def"}, {}})); | |
| encoded.set_start_end_bit_deltas( | |
| EncodeDeltas({kBeginEnd}, {{kBegin}, {kEnd}})); | |
| encoded.set_template_id_deltas(EncodeDeltas({1}, {{2}, {2}})); | |
| encoded.set_frame_id_deltas(EncodeDeltas({1}, {{3}, {3}})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 3); | |
| auto first_expected = DdBuilder().B().E().Tid(1).Fid(1).Ext("abc").Build(); | |
| auto second_expected = DdBuilder().B().Tid(2).Fid(3).Ext("def").Build(); | |
| auto third_expected = DdBuilder().E().Tid(2).Fid(3).Build(); | |
| ASSERT_THAT(decoded.ok(), Eq(true)); | |
| EXPECT_THAT(decoded.value(), | |
| ElementsAre(first_expected, second_expected, third_expected)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, MultiplePacketsOneFrame) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit(kBegin); | |
| encoded.set_template_id(1u); | |
| encoded.set_frame_id(1u); | |
| encoded.set_extended_infos(EncodeOptionalBlobs({{"abc"}, {}, {}})); | |
| encoded.set_start_end_bit_deltas(EncodeDeltas({kBegin}, {{kNone}, {kEnd}})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 3); | |
| auto first_expected = DdBuilder().B().Tid(1).Fid(1).Ext("abc").Build(); | |
| auto second_expected = DdBuilder().Tid(1).Fid(1).Build(); | |
| auto third_expected = DdBuilder().E().Tid(1).Fid(1).Build(); | |
| ASSERT_THAT(decoded.ok(), Eq(true)); | |
| EXPECT_THAT(decoded.value(), | |
| ElementsAre(first_expected, second_expected, third_expected)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, FirstPacketMissingDd) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_extended_infos(EncodeOptionalBlobs({{}, {}, {"three!"}})); | |
| encoded.set_start_end_bit_deltas(EncodeDeltas({}, {{kBeginEnd}, {kEnd}})); | |
| encoded.set_template_id_deltas(EncodeDeltas({}, {{1}, {2}})); | |
| encoded.set_frame_id_deltas(EncodeDeltas({}, {{1}, {3}})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 3); | |
| auto second_expected = DdBuilder().B().E().Tid(1).Fid(1).Build(); | |
| auto third_expected = DdBuilder().E().Tid(2).Fid(3).Ext("three!").Build(); | |
| ASSERT_THAT(decoded.ok(), Eq(true)); | |
| EXPECT_THAT(decoded.value(), | |
| ElementsAre(IsEmpty(), second_expected, third_expected)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, SomePacketMissingDd) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit(kBeginEnd); | |
| encoded.set_template_id(1u); | |
| encoded.set_frame_id(1u); | |
| encoded.set_extended_infos(EncodeOptionalBlobs({{}, {}, {}})); | |
| encoded.set_start_end_bit_deltas(EncodeDeltas({kBeginEnd}, {{}, {kEnd}})); | |
| encoded.set_template_id_deltas(EncodeDeltas({1}, {{}, {2}})); | |
| encoded.set_frame_id_deltas(EncodeDeltas({1}, {{}, {3}})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 3); | |
| auto first_expected = DdBuilder().B().E().Tid(1).Fid(1).Build(); | |
| auto third_expected = DdBuilder().E().Tid(2).Fid(3).Build(); | |
| ASSERT_THAT(decoded.ok(), Eq(true)); | |
| EXPECT_THAT(decoded.value(), | |
| ElementsAre(first_expected, IsEmpty(), third_expected)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, ExtendedWithoutRequiredFields) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit_deltas(EncodeDeltas({}, {{kNone}})); | |
| encoded.set_template_id_deltas(EncodeDeltas({}, {{1}})); | |
| encoded.set_frame_id_deltas(EncodeDeltas({}, {{1}})); | |
| encoded.set_extended_infos(EncodeOptionalBlobs({{"Should not be here"}, {}})); | |
| auto decoded = | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(encoded, 2); | |
| ASSERT_THAT(decoded.ok(), Eq(false)); | |
| } | |
| TEST(RtcEventLogDependencyDescriptorDecoding, MissingRequiredField) { | |
| rtclog2::DependencyDescriptorsWireInfo encoded; | |
| encoded.set_start_end_bit(kBeginEnd); | |
| encoded.set_template_id(1u); | |
| encoded.set_frame_id(1u); | |
| { | |
| rtclog2::DependencyDescriptorsWireInfo missing = encoded; | |
| missing.clear_start_end_bit(); | |
| EXPECT_THAT( | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(missing, 1).ok(), | |
| Eq(false)); | |
| } | |
| { | |
| rtclog2::DependencyDescriptorsWireInfo missing = encoded; | |
| missing.clear_template_id(); | |
| EXPECT_THAT( | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(missing, 1).ok(), | |
| Eq(false)); | |
| } | |
| { | |
| rtclog2::DependencyDescriptorsWireInfo missing = encoded; | |
| missing.clear_frame_id(); | |
| EXPECT_THAT( | |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode(missing, 1).ok(), | |
| Eq(false)); | |
| } | |
| } | |
| } // namespace | |
| } // namespace webrtc |