blob: ada4dea3a5c788653515c867b93fd6838a9f6f71 [file] [log] [blame]
// Copyright (c) 2023 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.
#ifndef QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_TEST_MESSAGE_H_
#define QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_TEST_MESSAGE_H_
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <optional>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/variant.h"
#include "quiche/quic/core/quic_data_reader.h"
#include "quiche/quic/core/quic_data_writer.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/moqt/moqt_messages.h"
#include "quiche/quic/platform/api/quic_logging.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/quiche_endian.h"
namespace moqt::test {
// Base class containing a wire image and the corresponding structured
// representation of an example of each message. It allows parser and framer
// tests to iterate through all message types without much specialized code.
class QUICHE_NO_EXPORT TestMessageBase {
public:
TestMessageBase(MoqtMessageType message_type) : message_type_(message_type) {}
virtual ~TestMessageBase() = default;
MoqtMessageType message_type() const { return message_type_; }
typedef absl::variant<MoqtClientSetup, MoqtServerSetup, MoqtObject,
MoqtSubscribeRequest, MoqtSubscribeOk,
MoqtSubscribeError, MoqtUnsubscribe, MoqtSubscribeFin,
MoqtSubscribeRst, MoqtAnnounce, MoqtAnnounceOk,
MoqtAnnounceError, MoqtUnannounce, MoqtGoAway>
MessageStructuredData;
// The total actual size of the message.
size_t total_message_size() const { return wire_image_size_; }
absl::string_view PacketSample() const {
return absl::string_view(wire_image_, wire_image_size_);
}
void set_wire_image_size(size_t wire_image_size) {
wire_image_size_ = wire_image_size;
}
// Returns a copy of the structured data for the message.
virtual MessageStructuredData structured_data() const = 0;
// Compares |values| to the derived class's structured data to make sure
// they are equal.
virtual bool EqualFieldValues(MessageStructuredData& values) const = 0;
// Expand all varints in the message. This is pure virtual because each
// message has a different layout of varints.
virtual void ExpandVarints() = 0;
protected:
void SetWireImage(uint8_t* wire_image, size_t wire_image_size) {
memcpy(wire_image_, wire_image, wire_image_size);
wire_image_size_ = wire_image_size;
}
// Expands all the varints in the message, alternating between making them 2,
// 4, and 8 bytes long. Updates length fields accordingly.
// Each character in |varints| corresponds to a byte in the original message.
// If there is a 'v', it is a varint that should be expanded. If '-', skip
// to the next byte.
void ExpandVarintsImpl(absl::string_view varints) {
int next_varint_len = 2;
char new_wire_image[kMaxMessageHeaderSize + 1];
quic::QuicDataReader reader(
absl::string_view(wire_image_, wire_image_size_));
quic::QuicDataWriter writer(sizeof(new_wire_image), new_wire_image);
size_t i = 0;
while (!reader.IsDoneReading()) {
if (i >= varints.length() || varints[i++] == '-') {
uint8_t byte;
reader.ReadUInt8(&byte);
writer.WriteUInt8(byte);
continue;
}
uint64_t value;
reader.ReadVarInt62(&value);
writer.WriteVarInt62WithForcedLength(
value, static_cast<quiche::QuicheVariableLengthIntegerLength>(
next_varint_len));
next_varint_len *= 2;
if (next_varint_len == 16) {
next_varint_len = 2;
}
}
memcpy(wire_image_, new_wire_image, writer.length());
wire_image_size_ = writer.length();
}
protected:
MoqtMessageType message_type_;
private:
char wire_image_[kMaxMessageHeaderSize + 20];
size_t wire_image_size_;
};
// Base class for the two subtypes of Object Message.
class QUICHE_NO_EXPORT ObjectMessage : public TestMessageBase {
public:
ObjectMessage(MoqtMessageType type) : TestMessageBase(type) {}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtObject>(values);
if (cast.track_id != object_.track_id) {
QUIC_LOG(INFO) << "OBJECT Track ID mismatch";
return false;
}
if (cast.group_sequence != object_.group_sequence) {
QUIC_LOG(INFO) << "OBJECT Group Sequence mismatch";
return false;
}
if (cast.object_sequence != object_.object_sequence) {
QUIC_LOG(INFO) << "OBJECT Object Sequence mismatch";
return false;
}
if (cast.object_send_order != object_.object_send_order) {
QUIC_LOG(INFO) << "OBJECT Object Send Order mismatch";
return false;
}
return true;
}
void ExpandVarints() override {
ExpandVarintsImpl("vvvvvv"); // first six fields are varints
}
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(object_);
}
protected:
MoqtObject object_ = {
/*track_id=*/4,
/*group_sequence=*/5,
/*object_sequence=*/6,
/*object_send_order=*/7,
/*payload_length=*/std::nullopt,
};
};
class QUICHE_NO_EXPORT ObjectMessageWithLength : public ObjectMessage {
public:
ObjectMessageWithLength()
: ObjectMessage(MoqtMessageType::kObjectWithPayloadLength) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
object_.payload_length = payload_length_;
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtObject>(values);
if (cast.payload_length != payload_length_) {
QUIC_LOG(INFO) << "OBJECT Payload Length mismatch";
return false;
}
return ObjectMessage::EqualFieldValues(values);
}
void ExpandVarints() override {
ExpandVarintsImpl("vvvvvv"); // first six fields are varints
}
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(object_);
}
private:
uint8_t raw_packet_[9] = {
0x00, 0x04, 0x05, 0x06, 0x07, // varints
0x03, 0x66, 0x6f, 0x6f, // payload = "foo"
};
std::optional<uint64_t> payload_length_ = 3;
};
class QUICHE_NO_EXPORT ObjectMessageWithoutLength : public ObjectMessage {
public:
ObjectMessageWithoutLength()
: ObjectMessage(MoqtMessageType::kObjectWithoutPayloadLength) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtObject>(values);
if (cast.payload_length != std::nullopt) {
QUIC_LOG(INFO) << "OBJECT Payload Length mismatch";
return false;
}
return ObjectMessage::EqualFieldValues(values);
}
void ExpandVarints() override {
ExpandVarintsImpl("vvvvv"); // first six fields are varints
}
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(object_);
}
private:
uint8_t raw_packet_[8] = {
0x02, 0x04, 0x05, 0x06, 0x07, // varints
0x66, 0x6f, 0x6f, // payload = "foo"
};
};
class QUICHE_NO_EXPORT ClientSetupMessage : public TestMessageBase {
public:
explicit ClientSetupMessage(bool webtrans)
: TestMessageBase(MoqtMessageType::kClientSetup) {
if (webtrans) {
// Should not send PATH.
client_setup_.path = std::nullopt;
raw_packet_[5] = 0x01; // only one parameter
SetWireImage(raw_packet_, sizeof(raw_packet_) - 5);
} else {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtClientSetup>(values);
if (cast.supported_versions.size() !=
client_setup_.supported_versions.size()) {
QUIC_LOG(INFO) << "CLIENT_SETUP number of supported versions mismatch";
return false;
}
for (uint64_t i = 0; i < cast.supported_versions.size(); ++i) {
// Listed versions are 1 and 2, in that order.
if (cast.supported_versions[i] != client_setup_.supported_versions[i]) {
QUIC_LOG(INFO) << "CLIENT_SETUP supported version mismatch";
return false;
}
}
if (cast.role != client_setup_.role) {
QUIC_LOG(INFO) << "CLIENT_SETUP role mismatch";
return false;
}
if (cast.path != client_setup_.path) {
QUIC_LOG(INFO) << "CLIENT_SETUP path mismatch";
return false;
}
return true;
}
void ExpandVarints() override {
if (client_setup_.path.has_value()) {
ExpandVarintsImpl("--vvvvvv-vv---");
// first two bytes are already a 2B varint. Also, don't expand parameter
// varints because that messes up the parameter length field.
} else {
ExpandVarintsImpl("--vvvvvv-");
}
}
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(client_setup_);
}
private:
uint8_t raw_packet_[14] = {
0x40, 0x40, // type
0x02, 0x01, 0x02, // versions
0x02, // 2 parameters
0x00, 0x01, 0x03, // role = both
0x01, 0x03, 0x66, 0x6f, 0x6f // path = "foo"
};
MoqtClientSetup client_setup_ = {
/*supported_versions=*/std::vector<MoqtVersion>(
{static_cast<MoqtVersion>(1), static_cast<MoqtVersion>(2)}),
/*role=*/MoqtRole::kBoth,
/*path=*/"foo",
};
};
class QUICHE_NO_EXPORT ServerSetupMessage : public TestMessageBase {
public:
explicit ServerSetupMessage()
: TestMessageBase(MoqtMessageType::kServerSetup) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtServerSetup>(values);
if (cast.selected_version != server_setup_.selected_version) {
QUIC_LOG(INFO) << "SERVER_SETUP selected version mismatch";
return false;
}
if (cast.role != server_setup_.role) {
QUIC_LOG(INFO) << "SERVER_SETUP role mismatch";
return false;
}
return true;
}
void ExpandVarints() override {
ExpandVarintsImpl("--v"); // first two bytes are already a 2b varint
}
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(server_setup_);
}
private:
uint8_t raw_packet_[4] = {
0x40, 0x41, // type
0x01, 0x00, // version, zero params
};
MoqtServerSetup server_setup_ = {
/*selected_version=*/static_cast<MoqtVersion>(1),
/*role=*/std::nullopt,
};
};
class QUICHE_NO_EXPORT SubscribeRequestMessage : public TestMessageBase {
public:
SubscribeRequestMessage()
: TestMessageBase(MoqtMessageType::kSubscribeRequest) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtSubscribeRequest>(values);
if (cast.track_namespace != subscribe_request_.track_namespace) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST track namespace mismatch";
return false;
}
if (cast.track_name != subscribe_request_.track_name) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST track name mismatch";
return false;
}
if (cast.start_group != subscribe_request_.start_group) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST start group mismatch";
return false;
}
if (cast.start_object != subscribe_request_.start_object) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST start object mismatch";
return false;
}
if (cast.end_group != subscribe_request_.end_group) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST end group mismatch";
return false;
}
if (cast.end_object != subscribe_request_.end_object) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST end object mismatch";
return false;
}
if (cast.authorization_info != subscribe_request_.authorization_info) {
QUIC_LOG(INFO) << "SUBSCRIBE REQUEST authorization info mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v----vvvvvvvvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_request_);
}
private:
uint8_t raw_packet_[22] = {
0x03, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x04, 0x61, 0x62, 0x63, 0x64, // track_name = "abcd"
0x02, 0x04, // start_group = 4 (relative previous)
0x01, 0x01, // start_object = 1 (absolute)
0x00, // end_group = none
0x00, // end_object = none
0x01, // 1 parameter
0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
MoqtSubscribeRequest subscribe_request_ = {
/*track_namespace=*/"foo",
/*track_name=*/"abcd",
/*start_group=*/MoqtSubscribeLocation(false, (int64_t)(-4)),
/*start_object=*/MoqtSubscribeLocation(true, (uint64_t)1),
/*end_group=*/std::nullopt,
/*end_object=*/std::nullopt,
/*authorization_info=*/"bar",
};
};
class QUICHE_NO_EXPORT SubscribeOkMessage : public TestMessageBase {
public:
SubscribeOkMessage() : TestMessageBase(MoqtMessageType::kSubscribeOk) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtSubscribeOk>(values);
if (cast.track_namespace != subscribe_ok_.track_namespace) {
QUIC_LOG(INFO) << "SUBSCRIBE OK track namespace mismatch";
return false;
}
if (cast.track_name != subscribe_ok_.track_name) {
QUIC_LOG(INFO) << "SUBSCRIBE OK track name mismatch";
return false;
}
if (cast.track_id != subscribe_ok_.track_id) {
QUIC_LOG(INFO) << "SUBSCRIBE OK track ID mismatch";
return false;
}
if (cast.expires != subscribe_ok_.expires) {
QUIC_LOG(INFO) << "SUBSCRIBE OK expiration mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v---vv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_ok_);
}
private:
uint8_t raw_packet_[11] = {
0x04, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x03, 0x62, 0x61, 0x72, // track_namespace = "bar"
0x01, // track_id = 1
0x02, // expires = 2
};
MoqtSubscribeOk subscribe_ok_ = {
/*track_namespace=*/"foo",
/*track_name=*/"bar",
/*track_id=*/1,
/*expires=*/quic::QuicTimeDelta::FromMilliseconds(2),
};
};
class QUICHE_NO_EXPORT SubscribeErrorMessage : public TestMessageBase {
public:
SubscribeErrorMessage() : TestMessageBase(MoqtMessageType::kSubscribeError) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtSubscribeError>(values);
if (cast.track_namespace != subscribe_error_.track_namespace) {
QUIC_LOG(INFO) << "SUBSCRIBE ERROR track namespace mismatch";
return false;
}
if (cast.track_name != subscribe_error_.track_name) {
QUIC_LOG(INFO) << "SUBSCRIBE ERROR track name mismatch";
return false;
}
if (cast.error_code != subscribe_error_.error_code) {
QUIC_LOG(INFO) << "SUBSCRIBE ERROR error code mismatch";
return false;
}
if (cast.reason_phrase != subscribe_error_.reason_phrase) {
QUIC_LOG(INFO) << "SUBSCRIBE ERROR reason phrase mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v---vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_error_);
}
private:
uint8_t raw_packet_[14] = {
0x05, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x03, 0x62, 0x61, 0x72, // track_namespace = "bar"
0x01, // error_code = 1
0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
};
MoqtSubscribeError subscribe_error_ = {
/*track_namespace=*/"foo",
/*track_name=*/"bar",
/*subscribe=*/1,
/*reason_phrase=*/"bar",
};
};
class QUICHE_NO_EXPORT UnsubscribeMessage : public TestMessageBase {
public:
UnsubscribeMessage() : TestMessageBase(MoqtMessageType::kUnsubscribe) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtUnsubscribe>(values);
if (cast.track_namespace != unsubscribe_.track_namespace) {
QUIC_LOG(INFO) << "UNSUBSCRIBE track name mismatch";
return false;
}
if (cast.track_name != unsubscribe_.track_name) {
QUIC_LOG(INFO) << "UNSUBSCRIBE track name mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(unsubscribe_);
}
private:
uint8_t raw_packet_[9] = {
0x0a, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x03, 0x62, 0x61, 0x72, // track_namespace = "bar"
};
MoqtUnsubscribe unsubscribe_ = {
/*track_namespace=*/"foo",
/*track_name=*/"bar",
};
};
class QUICHE_NO_EXPORT SubscribeFinMessage : public TestMessageBase {
public:
SubscribeFinMessage() : TestMessageBase(MoqtMessageType::kSubscribeFin) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtSubscribeFin>(values);
if (cast.track_namespace != subscribe_fin_.track_namespace) {
QUIC_LOG(INFO) << "SUBSCRIBE_FIN track name mismatch";
return false;
}
if (cast.track_name != subscribe_fin_.track_name) {
QUIC_LOG(INFO) << "SUBSCRIBE_FIN track name mismatch";
return false;
}
if (cast.final_group != subscribe_fin_.final_group) {
QUIC_LOG(INFO) << "SUBSCRIBE_FIN final group mismatch";
return false;
}
if (cast.final_object != subscribe_fin_.final_object) {
QUIC_LOG(INFO) << "SUBSCRIBE_FIN final object mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v---vv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_fin_);
}
private:
uint8_t raw_packet_[11] = {
0x0b, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x03, 0x62, 0x61, 0x72, // track_namespace = "bar"
0x08, // final_group = 8
0x0c, // final_object = 12
};
MoqtSubscribeFin subscribe_fin_ = {
/*track_namespace=*/"foo",
/*track_name=*/"bar",
/*final_group=*/8,
/*final_object=*/12,
};
};
class QUICHE_NO_EXPORT SubscribeRstMessage : public TestMessageBase {
public:
SubscribeRstMessage() : TestMessageBase(MoqtMessageType::kSubscribeRst) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtSubscribeRst>(values);
if (cast.track_namespace != subscribe_rst_.track_namespace) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST track name mismatch";
return false;
}
if (cast.track_name != subscribe_rst_.track_name) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST track name mismatch";
return false;
}
if (cast.error_code != subscribe_rst_.error_code) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST error code mismatch";
return false;
}
if (cast.reason_phrase != subscribe_rst_.reason_phrase) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST reason phrase mismatch";
return false;
}
if (cast.final_group != subscribe_rst_.final_group) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST final group mismatch";
return false;
}
if (cast.final_object != subscribe_rst_.final_object) {
QUIC_LOG(INFO) << "SUBSCRIBE_RST final object mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---v---vv--vv"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(subscribe_rst_);
}
private:
uint8_t raw_packet_[15] = {
0x0c, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x03, 0x62, 0x61, 0x72, // track_namespace = "bar"
0x03, // error_code = 3
0x02, 0x68, 0x69, // reason_phrase = "hi"
0x08, // final_group = 8
0x0c, // final_object = 12
};
MoqtSubscribeRst subscribe_rst_ = {
/*track_namespace=*/"foo",
/*track_name=*/"bar",
/*error_code=*/3,
/*reason_phrase=*/"hi",
/*final_group=*/8,
/*final_object=*/12,
};
};
class QUICHE_NO_EXPORT AnnounceMessage : public TestMessageBase {
public:
AnnounceMessage() : TestMessageBase(MoqtMessageType::kAnnounce) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtAnnounce>(values);
if (cast.track_namespace != announce_.track_namespace) {
QUIC_LOG(INFO) << "ANNOUNCE MESSAGE track namespace mismatch";
return false;
}
if (cast.authorization_info != announce_.authorization_info) {
QUIC_LOG(INFO) << "ANNOUNCE MESSAGE authorization info mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---vvv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_);
}
private:
uint8_t raw_packet_[11] = {
0x06, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x01, // 1 parameter
0x02, 0x03, 0x62, 0x61, 0x72, // authorization_info = "bar"
};
MoqtAnnounce announce_ = {
/*track_namespace=*/"foo",
/*authorization_info=*/"bar",
};
};
class QUICHE_NO_EXPORT AnnounceOkMessage : public TestMessageBase {
public:
AnnounceOkMessage() : TestMessageBase(MoqtMessageType::kAnnounceOk) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtAnnounceOk>(values);
if (cast.track_namespace != announce_ok_.track_namespace) {
QUIC_LOG(INFO) << "ANNOUNCE OK MESSAGE track namespace mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_ok_);
}
private:
uint8_t raw_packet_[5] = {
0x07, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
};
MoqtAnnounceOk announce_ok_ = {
/*track_namespace=*/"foo",
};
};
class QUICHE_NO_EXPORT AnnounceErrorMessage : public TestMessageBase {
public:
AnnounceErrorMessage() : TestMessageBase(MoqtMessageType::kAnnounceError) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtAnnounceError>(values);
if (cast.track_namespace != announce_error_.track_namespace) {
QUIC_LOG(INFO) << "ANNOUNCE ERROR track namespace mismatch";
return false;
}
if (cast.error_code != announce_error_.error_code) {
QUIC_LOG(INFO) << "ANNOUNCE ERROR error code mismatch";
return false;
}
if (cast.reason_phrase != announce_error_.reason_phrase) {
QUIC_LOG(INFO) << "ANNOUNCE ERROR reason phrase mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(announce_error_);
}
private:
uint8_t raw_packet_[10] = {
0x08, 0x03, 0x66, 0x6f, 0x6f, // track_namespace = "foo"
0x01, // error_code = 1
0x03, 0x62, 0x61, 0x72, // reason_phrase = "bar"
};
MoqtAnnounceError announce_error_ = {
/*track_namespace=*/"foo",
/*error_code=*/1,
/*reason_phrase=*/"bar",
};
};
class QUICHE_NO_EXPORT UnannounceMessage : public TestMessageBase {
public:
UnannounceMessage() : TestMessageBase(MoqtMessageType::kUnannounce) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtUnannounce>(values);
if (cast.track_namespace != unannounce_.track_namespace) {
QUIC_LOG(INFO) << "UNSUBSCRIBE full track name mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(unannounce_);
}
private:
uint8_t raw_packet_[5] = {
0x09, 0x03, 0x66, 0x6f, 0x6f, // track_namespace
};
MoqtUnannounce unannounce_ = {
/*track_namespace=*/"foo",
};
};
class QUICHE_NO_EXPORT GoAwayMessage : public TestMessageBase {
public:
GoAwayMessage() : TestMessageBase(MoqtMessageType::kGoAway) {
SetWireImage(raw_packet_, sizeof(raw_packet_));
}
bool EqualFieldValues(MessageStructuredData& values) const override {
auto cast = std::get<MoqtGoAway>(values);
if (cast.new_session_uri != goaway_.new_session_uri) {
QUIC_LOG(INFO) << "UNSUBSCRIBE full track name mismatch";
return false;
}
return true;
}
void ExpandVarints() override { ExpandVarintsImpl("vv---"); }
MessageStructuredData structured_data() const override {
return TestMessageBase::MessageStructuredData(goaway_);
}
private:
uint8_t raw_packet_[5] = {
0x10, 0x03, 0x66, 0x6f, 0x6f,
};
MoqtGoAway goaway_ = {
/*new_session_uri=*/"foo",
};
};
} // namespace moqt::test
#endif // QUICHE_QUIC_MOQT_TEST_TOOLS_MOQT_TEST_MESSAGE_H_