xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/moqt/moqt_parser_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2023 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/moqt/moqt_parser.h"
6 
7 #include <cstddef>
8 #include <cstdint>
9 #include <cstring>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <utility>
14 #include <vector>
15 
16 #include "absl/strings/string_view.h"
17 #include "quiche/quic/core/quic_data_writer.h"
18 #include "quiche/quic/moqt/moqt_messages.h"
19 #include "quiche/quic/moqt/test_tools/moqt_test_message.h"
20 #include "quiche/quic/platform/api/quic_test.h"
21 
22 namespace moqt::test {
23 
24 namespace {
25 
IsObjectMessage(MoqtMessageType type)26 inline bool IsObjectMessage(MoqtMessageType type) {
27   return (type == MoqtMessageType::kObjectStream ||
28           type == MoqtMessageType::kObjectDatagram ||
29           type == MoqtMessageType::kStreamHeaderTrack ||
30           type == MoqtMessageType::kStreamHeaderGroup);
31 }
32 
IsObjectWithoutPayloadLength(MoqtMessageType type)33 inline bool IsObjectWithoutPayloadLength(MoqtMessageType type) {
34   return (type == MoqtMessageType::kObjectStream ||
35           type == MoqtMessageType::kObjectDatagram);
36 }
37 
38 std::vector<MoqtMessageType> message_types = {
39     MoqtMessageType::kObjectStream,
40     // kObjectDatagram is a unique set of tests.
41     MoqtMessageType::kSubscribe,
42     MoqtMessageType::kSubscribeOk,
43     MoqtMessageType::kSubscribeError,
44     MoqtMessageType::kUnsubscribe,
45     MoqtMessageType::kSubscribeDone,
46     MoqtMessageType::kAnnounce,
47     MoqtMessageType::kAnnounceOk,
48     MoqtMessageType::kAnnounceError,
49     MoqtMessageType::kUnannounce,
50     MoqtMessageType::kClientSetup,
51     MoqtMessageType::kServerSetup,
52     MoqtMessageType::kStreamHeaderTrack,
53     MoqtMessageType::kStreamHeaderGroup,
54     MoqtMessageType::kGoAway,
55 };
56 
57 }  // namespace
58 
59 struct MoqtParserTestParams {
MoqtParserTestParamsmoqt::test::MoqtParserTestParams60   MoqtParserTestParams(MoqtMessageType message_type, bool uses_web_transport)
61       : message_type(message_type), uses_web_transport(uses_web_transport) {}
62   MoqtMessageType message_type;
63   bool uses_web_transport;
64 };
65 
GetMoqtParserTestParams()66 std::vector<MoqtParserTestParams> GetMoqtParserTestParams() {
67   std::vector<MoqtParserTestParams> params;
68 
69   std::vector<bool> uses_web_transport_bool = {
70       false,
71       true,
72   };
73   for (const MoqtMessageType message_type : message_types) {
74     if (message_type == MoqtMessageType::kClientSetup) {
75       for (const bool uses_web_transport : uses_web_transport_bool) {
76         params.push_back(
77             MoqtParserTestParams(message_type, uses_web_transport));
78       }
79     } else {
80       // All other types are processed the same for either perspective or
81       // transport.
82       params.push_back(MoqtParserTestParams(message_type, true));
83     }
84   }
85   return params;
86 }
87 
ParamNameFormatter(const testing::TestParamInfo<MoqtParserTestParams> & info)88 std::string ParamNameFormatter(
89     const testing::TestParamInfo<MoqtParserTestParams>& info) {
90   return MoqtMessageTypeToString(info.param.message_type) + "_" +
91          (info.param.uses_web_transport ? "WebTransport" : "QUIC");
92 }
93 
94 class MoqtParserTestVisitor : public MoqtParserVisitor {
95  public:
96   ~MoqtParserTestVisitor() = default;
97 
OnObjectMessage(const MoqtObject & message,absl::string_view payload,bool end_of_message)98   void OnObjectMessage(const MoqtObject& message, absl::string_view payload,
99                        bool end_of_message) override {
100     MoqtObject object = message;
101     object_payload_ = payload;
102     end_of_message_ = end_of_message;
103     messages_received_++;
104     last_message_ = TestMessageBase::MessageStructuredData(object);
105   }
106 
107   template <typename Message>
OnControlMessage(const Message & message)108   void OnControlMessage(const Message& message) {
109     end_of_message_ = true;
110     ++messages_received_;
111     last_message_ = TestMessageBase::MessageStructuredData(message);
112   }
OnClientSetupMessage(const MoqtClientSetup & message)113   void OnClientSetupMessage(const MoqtClientSetup& message) override {
114     OnControlMessage(message);
115   }
OnServerSetupMessage(const MoqtServerSetup & message)116   void OnServerSetupMessage(const MoqtServerSetup& message) override {
117     OnControlMessage(message);
118   }
OnSubscribeMessage(const MoqtSubscribe & message)119   void OnSubscribeMessage(const MoqtSubscribe& message) override {
120     OnControlMessage(message);
121   }
OnSubscribeOkMessage(const MoqtSubscribeOk & message)122   void OnSubscribeOkMessage(const MoqtSubscribeOk& message) override {
123     OnControlMessage(message);
124   }
OnSubscribeErrorMessage(const MoqtSubscribeError & message)125   void OnSubscribeErrorMessage(const MoqtSubscribeError& message) override {
126     OnControlMessage(message);
127   }
OnUnsubscribeMessage(const MoqtUnsubscribe & message)128   void OnUnsubscribeMessage(const MoqtUnsubscribe& message) override {
129     OnControlMessage(message);
130   }
OnSubscribeDoneMessage(const MoqtSubscribeDone & message)131   void OnSubscribeDoneMessage(const MoqtSubscribeDone& message) override {
132     OnControlMessage(message);
133   }
OnAnnounceMessage(const MoqtAnnounce & message)134   void OnAnnounceMessage(const MoqtAnnounce& message) override {
135     OnControlMessage(message);
136   }
OnAnnounceOkMessage(const MoqtAnnounceOk & message)137   void OnAnnounceOkMessage(const MoqtAnnounceOk& message) override {
138     OnControlMessage(message);
139   }
OnAnnounceErrorMessage(const MoqtAnnounceError & message)140   void OnAnnounceErrorMessage(const MoqtAnnounceError& message) override {
141     OnControlMessage(message);
142   }
OnUnannounceMessage(const MoqtUnannounce & message)143   void OnUnannounceMessage(const MoqtUnannounce& message) override {
144     OnControlMessage(message);
145   }
OnGoAwayMessage(const MoqtGoAway & message)146   void OnGoAwayMessage(const MoqtGoAway& message) override {
147     OnControlMessage(message);
148   }
OnParsingError(MoqtError code,absl::string_view reason)149   void OnParsingError(MoqtError code, absl::string_view reason) override {
150     QUIC_LOG(INFO) << "Parsing error: " << reason;
151     parsing_error_ = reason;
152     parsing_error_code_ = code;
153   }
154 
155   std::optional<absl::string_view> object_payload_;
156   bool end_of_message_ = false;
157   std::optional<absl::string_view> parsing_error_;
158   MoqtError parsing_error_code_;
159   uint64_t messages_received_ = 0;
160   std::optional<TestMessageBase::MessageStructuredData> last_message_;
161 };
162 
163 class MoqtParserTest
164     : public quic::test::QuicTestWithParam<MoqtParserTestParams> {
165  public:
MoqtParserTest()166   MoqtParserTest()
167       : message_type_(GetParam().message_type),
168         webtrans_(GetParam().uses_web_transport),
169         parser_(GetParam().uses_web_transport, visitor_) {}
170 
MakeMessage(MoqtMessageType message_type)171   std::unique_ptr<TestMessageBase> MakeMessage(MoqtMessageType message_type) {
172     return CreateTestMessage(message_type, webtrans_);
173   }
174 
175   MoqtParserTestVisitor visitor_;
176   MoqtMessageType message_type_;
177   bool webtrans_;
178   MoqtParser parser_;
179 };
180 
181 INSTANTIATE_TEST_SUITE_P(MoqtParserTests, MoqtParserTest,
182                          testing::ValuesIn(GetMoqtParserTestParams()),
183                          ParamNameFormatter);
184 
TEST_P(MoqtParserTest,OneMessage)185 TEST_P(MoqtParserTest, OneMessage) {
186   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
187   parser_.ProcessData(message->PacketSample(), true);
188   EXPECT_EQ(visitor_.messages_received_, 1);
189   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
190   EXPECT_TRUE(visitor_.end_of_message_);
191   if (IsObjectMessage(message_type_)) {
192     // Check payload message.
193     EXPECT_TRUE(visitor_.object_payload_.has_value());
194     EXPECT_EQ(*(visitor_.object_payload_), "foo");
195   }
196 }
197 
TEST_P(MoqtParserTest,OneMessageWithLongVarints)198 TEST_P(MoqtParserTest, OneMessageWithLongVarints) {
199   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
200   message->ExpandVarints();
201   parser_.ProcessData(message->PacketSample(), true);
202   EXPECT_EQ(visitor_.messages_received_, 1);
203   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
204   EXPECT_TRUE(visitor_.end_of_message_);
205   if (IsObjectMessage(message_type_)) {
206     // Check payload message.
207     EXPECT_EQ(visitor_.object_payload_, "foo");
208   }
209   EXPECT_FALSE(visitor_.parsing_error_.has_value());
210 }
211 
TEST_P(MoqtParserTest,TwoPartMessage)212 TEST_P(MoqtParserTest, TwoPartMessage) {
213   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
214   // The test Object message has payload for less then half the message length,
215   // so splitting the message in half will prevent the first half from being
216   // processed.
217   size_t first_data_size = message->total_message_size() / 2;
218   if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
219     // The boundary happens to fall right after the stream header, so move it.
220     ++first_data_size;
221   }
222   parser_.ProcessData(message->PacketSample().substr(0, first_data_size),
223                       false);
224   EXPECT_EQ(visitor_.messages_received_, 0);
225   parser_.ProcessData(
226       message->PacketSample().substr(
227           first_data_size, message->total_message_size() - first_data_size),
228       true);
229   EXPECT_EQ(visitor_.messages_received_, 1);
230   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
231   if (IsObjectMessage(message_type_)) {
232     EXPECT_EQ(visitor_.object_payload_, "foo");
233   }
234   EXPECT_TRUE(visitor_.end_of_message_);
235   EXPECT_FALSE(visitor_.parsing_error_.has_value());
236 }
237 
TEST_P(MoqtParserTest,OneByteAtATime)238 TEST_P(MoqtParserTest, OneByteAtATime) {
239   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
240   size_t kObjectPayloadSize = 3;
241   for (size_t i = 0; i < message->total_message_size(); ++i) {
242     if (!IsObjectMessage(message_type_)) {
243       EXPECT_EQ(visitor_.messages_received_, 0);
244     }
245     EXPECT_FALSE(visitor_.end_of_message_);
246     parser_.ProcessData(message->PacketSample().substr(i, 1), false);
247   }
248   EXPECT_EQ(visitor_.messages_received_,
249             (IsObjectMessage(message_type_) ? (kObjectPayloadSize + 1) : 1));
250   if (IsObjectWithoutPayloadLength(message_type_)) {
251     EXPECT_FALSE(visitor_.end_of_message_);
252     parser_.ProcessData(absl::string_view(), true);  // Needs the FIN
253     EXPECT_EQ(visitor_.messages_received_, kObjectPayloadSize + 2);
254   }
255   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
256   EXPECT_TRUE(visitor_.end_of_message_);
257   EXPECT_FALSE(visitor_.parsing_error_.has_value());
258 }
259 
TEST_P(MoqtParserTest,OneByteAtATimeLongerVarints)260 TEST_P(MoqtParserTest, OneByteAtATimeLongerVarints) {
261   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
262   message->ExpandVarints();
263   size_t kObjectPayloadSize = 3;
264   for (size_t i = 0; i < message->total_message_size(); ++i) {
265     if (!IsObjectMessage(message_type_)) {
266       EXPECT_EQ(visitor_.messages_received_, 0);
267     }
268     EXPECT_FALSE(visitor_.end_of_message_);
269     parser_.ProcessData(message->PacketSample().substr(i, 1), false);
270   }
271   EXPECT_EQ(visitor_.messages_received_,
272             (IsObjectMessage(message_type_) ? (kObjectPayloadSize + 1) : 1));
273   if (IsObjectWithoutPayloadLength(message_type_)) {
274     EXPECT_FALSE(visitor_.end_of_message_);
275     parser_.ProcessData(absl::string_view(), true);  // Needs the FIN
276     EXPECT_EQ(visitor_.messages_received_, kObjectPayloadSize + 2);
277   }
278   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
279   EXPECT_TRUE(visitor_.end_of_message_);
280   EXPECT_FALSE(visitor_.parsing_error_.has_value());
281 }
282 
TEST_P(MoqtParserTest,EarlyFin)283 TEST_P(MoqtParserTest, EarlyFin) {
284   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
285   size_t first_data_size = message->total_message_size() / 2;
286   if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
287     // The boundary happens to fall right after the stream header, so move it.
288     ++first_data_size;
289   }
290   parser_.ProcessData(message->PacketSample().substr(0, first_data_size), true);
291   EXPECT_EQ(visitor_.messages_received_, 0);
292   EXPECT_TRUE(visitor_.parsing_error_.has_value());
293   EXPECT_EQ(*visitor_.parsing_error_, "FIN after incomplete message");
294 }
295 
TEST_P(MoqtParserTest,SeparateEarlyFin)296 TEST_P(MoqtParserTest, SeparateEarlyFin) {
297   std::unique_ptr<TestMessageBase> message = MakeMessage(message_type_);
298   size_t first_data_size = message->total_message_size() / 2;
299   if (message_type_ == MoqtMessageType::kStreamHeaderTrack) {
300     // The boundary happens to fall right after the stream header, so move it.
301     ++first_data_size;
302   }
303   parser_.ProcessData(message->PacketSample().substr(0, first_data_size),
304                       false);
305   parser_.ProcessData(absl::string_view(), true);
306   EXPECT_EQ(visitor_.messages_received_, 0);
307   EXPECT_TRUE(visitor_.parsing_error_.has_value());
308   EXPECT_EQ(*visitor_.parsing_error_, "End of stream before complete message");
309   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
310 }
311 
312 // Tests for message-specific error cases, and behaviors for a single message
313 // type.
314 class MoqtMessageSpecificTest : public quic::test::QuicTest {
315  public:
MoqtMessageSpecificTest()316   MoqtMessageSpecificTest() {}
317 
318   MoqtParserTestVisitor visitor_;
319 
320   static constexpr bool kWebTrans = true;
321   static constexpr bool kRawQuic = false;
322 };
323 
TEST_F(MoqtMessageSpecificTest,ObjectStreamSeparateFin)324 TEST_F(MoqtMessageSpecificTest, ObjectStreamSeparateFin) {
325   // OBJECT can return on an unknown-length message even without receiving a
326   // FIN.
327   MoqtParser parser(kRawQuic, visitor_);
328   auto message = std::make_unique<ObjectStreamMessage>();
329   parser.ProcessData(message->PacketSample(), false);
330   EXPECT_EQ(visitor_.messages_received_, 1);
331   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
332   EXPECT_TRUE(visitor_.object_payload_.has_value());
333   EXPECT_EQ(*(visitor_.object_payload_), "foo");
334   EXPECT_FALSE(visitor_.end_of_message_);
335 
336   parser.ProcessData(absl::string_view(), true);  // send the FIN
337   EXPECT_EQ(visitor_.messages_received_, 2);
338   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
339   EXPECT_TRUE(visitor_.object_payload_.has_value());
340   EXPECT_EQ(*(visitor_.object_payload_), "");
341   EXPECT_TRUE(visitor_.end_of_message_);
342   EXPECT_FALSE(visitor_.parsing_error_.has_value());
343 }
344 
345 // Send the header + some payload, pure payload, then pure payload to end the
346 // message.
TEST_F(MoqtMessageSpecificTest,ThreePartObject)347 TEST_F(MoqtMessageSpecificTest, ThreePartObject) {
348   MoqtParser parser(kRawQuic, visitor_);
349   auto message = std::make_unique<ObjectStreamMessage>();
350   parser.ProcessData(message->PacketSample(), false);
351   EXPECT_EQ(visitor_.messages_received_, 1);
352   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
353   EXPECT_FALSE(visitor_.end_of_message_);
354   EXPECT_TRUE(visitor_.object_payload_.has_value());
355   EXPECT_EQ(*(visitor_.object_payload_), "foo");
356 
357   // second part
358   parser.ProcessData("bar", false);
359   EXPECT_EQ(visitor_.messages_received_, 2);
360   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
361   EXPECT_FALSE(visitor_.end_of_message_);
362   EXPECT_TRUE(visitor_.object_payload_.has_value());
363   EXPECT_EQ(*(visitor_.object_payload_), "bar");
364 
365   // third part includes FIN
366   parser.ProcessData("deadbeef", true);
367   EXPECT_EQ(visitor_.messages_received_, 3);
368   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
369   EXPECT_TRUE(visitor_.end_of_message_);
370   EXPECT_TRUE(visitor_.object_payload_.has_value());
371   EXPECT_EQ(*(visitor_.object_payload_), "deadbeef");
372   EXPECT_FALSE(visitor_.parsing_error_.has_value());
373 }
374 
375 // Send the part of header, rest of header + payload, plus payload.
TEST_F(MoqtMessageSpecificTest,ThreePartObjectFirstIncomplete)376 TEST_F(MoqtMessageSpecificTest, ThreePartObjectFirstIncomplete) {
377   MoqtParser parser(kRawQuic, visitor_);
378   auto message = std::make_unique<ObjectStreamMessage>();
379 
380   // first part
381   parser.ProcessData(message->PacketSample().substr(0, 4), false);
382   EXPECT_EQ(visitor_.messages_received_, 0);
383 
384   // second part. Add padding to it.
385   message->set_wire_image_size(100);
386   parser.ProcessData(
387       message->PacketSample().substr(4, message->total_message_size() - 4),
388       false);
389   EXPECT_EQ(visitor_.messages_received_, 1);
390   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
391   EXPECT_FALSE(visitor_.end_of_message_);
392   EXPECT_TRUE(visitor_.object_payload_.has_value());
393   EXPECT_EQ(visitor_.object_payload_->length(), 94);
394 
395   // third part includes FIN
396   parser.ProcessData("bar", true);
397   EXPECT_EQ(visitor_.messages_received_, 2);
398   EXPECT_TRUE(message->EqualFieldValues(*visitor_.last_message_));
399   EXPECT_TRUE(visitor_.end_of_message_);
400   EXPECT_TRUE(visitor_.object_payload_.has_value());
401   EXPECT_EQ(*(visitor_.object_payload_), "bar");
402   EXPECT_FALSE(visitor_.parsing_error_.has_value());
403 }
404 
TEST_F(MoqtMessageSpecificTest,StreamHeaderGroupFollowOn)405 TEST_F(MoqtMessageSpecificTest, StreamHeaderGroupFollowOn) {
406   MoqtParser parser(kRawQuic, visitor_);
407   // first part
408   auto message1 = std::make_unique<StreamHeaderGroupMessage>();
409   parser.ProcessData(message1->PacketSample(), false);
410   EXPECT_EQ(visitor_.messages_received_, 1);
411   EXPECT_TRUE(message1->EqualFieldValues(*visitor_.last_message_));
412   EXPECT_TRUE(visitor_.end_of_message_);
413   EXPECT_TRUE(visitor_.object_payload_.has_value());
414   EXPECT_EQ(*(visitor_.object_payload_), "foo");
415   EXPECT_FALSE(visitor_.parsing_error_.has_value());
416   // second part
417   auto message2 = std::make_unique<StreamMiddlerGroupMessage>();
418   parser.ProcessData(message2->PacketSample(), false);
419   EXPECT_EQ(visitor_.messages_received_, 2);
420   EXPECT_TRUE(message2->EqualFieldValues(*visitor_.last_message_));
421   EXPECT_TRUE(visitor_.end_of_message_);
422   EXPECT_TRUE(visitor_.object_payload_.has_value());
423   EXPECT_EQ(*(visitor_.object_payload_), "bar");
424   EXPECT_FALSE(visitor_.parsing_error_.has_value());
425 }
426 
TEST_F(MoqtMessageSpecificTest,StreamHeaderTrackFollowOn)427 TEST_F(MoqtMessageSpecificTest, StreamHeaderTrackFollowOn) {
428   MoqtParser parser(kRawQuic, visitor_);
429   // first part
430   auto message1 = std::make_unique<StreamHeaderTrackMessage>();
431   parser.ProcessData(message1->PacketSample(), false);
432   EXPECT_EQ(visitor_.messages_received_, 1);
433   EXPECT_TRUE(message1->EqualFieldValues(*visitor_.last_message_));
434   EXPECT_TRUE(visitor_.end_of_message_);
435   EXPECT_TRUE(visitor_.object_payload_.has_value());
436   EXPECT_EQ(*(visitor_.object_payload_), "foo");
437   EXPECT_FALSE(visitor_.parsing_error_.has_value());
438   // second part
439   auto message2 = std::make_unique<StreamMiddlerTrackMessage>();
440   parser.ProcessData(message2->PacketSample(), false);
441   EXPECT_EQ(visitor_.messages_received_, 2);
442   EXPECT_TRUE(message2->EqualFieldValues(*visitor_.last_message_));
443   EXPECT_TRUE(visitor_.end_of_message_);
444   EXPECT_TRUE(visitor_.object_payload_.has_value());
445   EXPECT_EQ(*(visitor_.object_payload_), "bar");
446   EXPECT_FALSE(visitor_.parsing_error_.has_value());
447 }
448 
TEST_F(MoqtMessageSpecificTest,ClientSetupRoleIsInvalid)449 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsInvalid) {
450   MoqtParser parser(kRawQuic, visitor_);
451   char setup[] = {
452       0x40, 0x40, 0x02, 0x01, 0x02,  // versions
453       0x03,                          // 3 params
454       0x00, 0x01, 0x04,              // role = invalid
455       0x01, 0x03, 0x66, 0x6f, 0x6f   // path = "foo"
456   };
457   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
458   EXPECT_EQ(visitor_.messages_received_, 0);
459   EXPECT_TRUE(visitor_.parsing_error_.has_value());
460   EXPECT_EQ(*visitor_.parsing_error_, "Invalid ROLE parameter");
461   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
462 }
463 
TEST_F(MoqtMessageSpecificTest,ServerSetupRoleIsInvalid)464 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsInvalid) {
465   MoqtParser parser(kRawQuic, visitor_);
466   char setup[] = {
467       0x40, 0x41, 0x01,
468       0x01,                         // 1 param
469       0x00, 0x01, 0x04,             // role = invalid
470       0x01, 0x03, 0x66, 0x6f, 0x6f  // path = "foo"
471   };
472   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
473   EXPECT_EQ(visitor_.messages_received_, 0);
474   EXPECT_TRUE(visitor_.parsing_error_.has_value());
475   EXPECT_EQ(*visitor_.parsing_error_, "Invalid ROLE parameter");
476   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
477 }
478 
TEST_F(MoqtMessageSpecificTest,SetupRoleAppearsTwice)479 TEST_F(MoqtMessageSpecificTest, SetupRoleAppearsTwice) {
480   MoqtParser parser(kRawQuic, visitor_);
481   char setup[] = {
482       0x40, 0x40, 0x02, 0x01, 0x02,  // versions
483       0x03,                          // 3 params
484       0x00, 0x01, 0x03,              // role = PubSub
485       0x00, 0x01, 0x03,              // role = PubSub
486       0x01, 0x03, 0x66, 0x6f, 0x6f   // path = "foo"
487   };
488   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
489   EXPECT_EQ(visitor_.messages_received_, 0);
490   EXPECT_TRUE(visitor_.parsing_error_.has_value());
491   EXPECT_EQ(*visitor_.parsing_error_, "ROLE parameter appears twice in SETUP");
492   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
493 }
494 
TEST_F(MoqtMessageSpecificTest,ClientSetupRoleIsMissing)495 TEST_F(MoqtMessageSpecificTest, ClientSetupRoleIsMissing) {
496   MoqtParser parser(kRawQuic, visitor_);
497   char setup[] = {
498       0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
499       0x01,                          // 1 param
500       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
501   };
502   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
503   EXPECT_EQ(visitor_.messages_received_, 0);
504   EXPECT_TRUE(visitor_.parsing_error_.has_value());
505   EXPECT_EQ(*visitor_.parsing_error_,
506             "ROLE parameter missing from CLIENT_SETUP message");
507   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
508 }
509 
TEST_F(MoqtMessageSpecificTest,ServerSetupRoleIsMissing)510 TEST_F(MoqtMessageSpecificTest, ServerSetupRoleIsMissing) {
511   MoqtParser parser(kRawQuic, visitor_);
512   char setup[] = {
513       0x40, 0x41, 0x01, 0x00,  // 1 param
514   };
515   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
516   EXPECT_EQ(visitor_.messages_received_, 0);
517   EXPECT_TRUE(visitor_.parsing_error_.has_value());
518   EXPECT_EQ(*visitor_.parsing_error_,
519             "ROLE parameter missing from SERVER_SETUP message");
520   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
521 }
522 
TEST_F(MoqtMessageSpecificTest,SetupRoleVarintLengthIsWrong)523 TEST_F(MoqtMessageSpecificTest, SetupRoleVarintLengthIsWrong) {
524   MoqtParser parser(kRawQuic, visitor_);
525   char setup[] = {
526       0x40, 0x40,                   // type
527       0x02, 0x01, 0x02,             // versions
528       0x02,                         // 2 parameters
529       0x00, 0x02, 0x03,             // role = PubSub, but length is 2
530       0x01, 0x03, 0x66, 0x6f, 0x6f  // path = "foo"
531   };
532   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
533   EXPECT_EQ(visitor_.messages_received_, 0);
534   EXPECT_TRUE(visitor_.parsing_error_.has_value());
535   EXPECT_EQ(*visitor_.parsing_error_,
536             "Parameter length does not match varint encoding");
537 
538   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kParameterLengthMismatch);
539 }
540 
TEST_F(MoqtMessageSpecificTest,SetupPathFromServer)541 TEST_F(MoqtMessageSpecificTest, SetupPathFromServer) {
542   MoqtParser parser(kRawQuic, visitor_);
543   char setup[] = {
544       0x40, 0x41,
545       0x01,                          // version = 1
546       0x01,                          // 1 param
547       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
548   };
549   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
550   EXPECT_EQ(visitor_.messages_received_, 0);
551   EXPECT_TRUE(visitor_.parsing_error_.has_value());
552   EXPECT_EQ(*visitor_.parsing_error_, "PATH parameter in SERVER_SETUP");
553   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
554 }
555 
TEST_F(MoqtMessageSpecificTest,SetupPathAppearsTwice)556 TEST_F(MoqtMessageSpecificTest, SetupPathAppearsTwice) {
557   MoqtParser parser(kRawQuic, visitor_);
558   char setup[] = {
559       0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
560       0x03,                          // 3 params
561       0x00, 0x01, 0x03,              // role = PubSub
562       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
563       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
564   };
565   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
566   EXPECT_EQ(visitor_.messages_received_, 0);
567   EXPECT_TRUE(visitor_.parsing_error_.has_value());
568   EXPECT_EQ(*visitor_.parsing_error_,
569             "PATH parameter appears twice in CLIENT_SETUP");
570   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
571 }
572 
TEST_F(MoqtMessageSpecificTest,SetupPathOverWebtrans)573 TEST_F(MoqtMessageSpecificTest, SetupPathOverWebtrans) {
574   MoqtParser parser(kWebTrans, visitor_);
575   char setup[] = {
576       0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
577       0x02,                          // 2 params
578       0x00, 0x01, 0x03,              // role = PubSub
579       0x01, 0x03, 0x66, 0x6f, 0x6f,  // path = "foo"
580   };
581   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
582   EXPECT_EQ(visitor_.messages_received_, 0);
583   EXPECT_TRUE(visitor_.parsing_error_.has_value());
584   EXPECT_EQ(*visitor_.parsing_error_,
585             "WebTransport connection is using PATH parameter in SETUP");
586   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
587 }
588 
TEST_F(MoqtMessageSpecificTest,SetupPathMissing)589 TEST_F(MoqtMessageSpecificTest, SetupPathMissing) {
590   MoqtParser parser(kRawQuic, visitor_);
591   char setup[] = {
592       0x40, 0x40, 0x02, 0x01, 0x02,  // versions = 1, 2
593       0x01,                          // 1 param
594       0x00, 0x01, 0x03,              // role = PubSub
595   };
596   parser.ProcessData(absl::string_view(setup, sizeof(setup)), false);
597   EXPECT_EQ(visitor_.messages_received_, 0);
598   EXPECT_TRUE(visitor_.parsing_error_.has_value());
599   EXPECT_EQ(*visitor_.parsing_error_,
600             "PATH SETUP parameter missing from Client message over QUIC");
601   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
602 }
603 
TEST_F(MoqtMessageSpecificTest,SubscribeAuthorizationInfoTwice)604 TEST_F(MoqtMessageSpecificTest, SubscribeAuthorizationInfoTwice) {
605   MoqtParser parser(kWebTrans, visitor_);
606   char subscribe[] = {
607       0x03, 0x01, 0x02, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
608       0x04, 0x61, 0x62, 0x63, 0x64,              // track_name = "abcd"
609       0x02, 0x04,                    // start_group = 4 (relative previous)
610       0x01, 0x01,                    // start_object = 1 (absolute)
611       0x00,                          // end_group = none
612       0x00,                          // end_object = none
613       0x02,                          // two params
614       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
615       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
616   };
617   parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
618   EXPECT_EQ(visitor_.messages_received_, 0);
619   EXPECT_TRUE(visitor_.parsing_error_.has_value());
620   EXPECT_EQ(*visitor_.parsing_error_,
621             "AUTHORIZATION_INFO parameter appears twice in SUBSCRIBE_REQUEST");
622   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
623 }
624 
TEST_F(MoqtMessageSpecificTest,AnnounceAuthorizationInfoTwice)625 TEST_F(MoqtMessageSpecificTest, AnnounceAuthorizationInfoTwice) {
626   MoqtParser parser(kWebTrans, visitor_);
627   char announce[] = {
628       0x06, 0x03, 0x66, 0x6f, 0x6f,  // track_namespace = "foo"
629       0x02,                          // 2 params
630       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
631       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
632   };
633   parser.ProcessData(absl::string_view(announce, sizeof(announce)), false);
634   EXPECT_EQ(visitor_.messages_received_, 0);
635   EXPECT_TRUE(visitor_.parsing_error_.has_value());
636   EXPECT_EQ(*visitor_.parsing_error_,
637             "AUTHORIZATION_INFO parameter appears twice in ANNOUNCE");
638   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
639 }
640 
TEST_F(MoqtMessageSpecificTest,FinMidPayload)641 TEST_F(MoqtMessageSpecificTest, FinMidPayload) {
642   MoqtParser parser(kRawQuic, visitor_);
643   auto message = std::make_unique<StreamHeaderGroupMessage>();
644   parser.ProcessData(
645       message->PacketSample().substr(0, message->total_message_size() - 1),
646       true);
647   EXPECT_EQ(visitor_.messages_received_, 0);
648   EXPECT_TRUE(visitor_.parsing_error_.has_value());
649   EXPECT_EQ(*visitor_.parsing_error_, "Received FIN mid-payload");
650   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
651 }
652 
TEST_F(MoqtMessageSpecificTest,PartialPayloadThenFin)653 TEST_F(MoqtMessageSpecificTest, PartialPayloadThenFin) {
654   MoqtParser parser(kRawQuic, visitor_);
655   auto message = std::make_unique<StreamHeaderTrackMessage>();
656   parser.ProcessData(
657       message->PacketSample().substr(0, message->total_message_size() - 1),
658       false);
659   parser.ProcessData(absl::string_view(), true);
660   EXPECT_EQ(visitor_.messages_received_, 1);
661   EXPECT_TRUE(visitor_.parsing_error_.has_value());
662   EXPECT_EQ(*visitor_.parsing_error_,
663             "End of stream before complete OBJECT PAYLOAD");
664   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
665 }
666 
TEST_F(MoqtMessageSpecificTest,DataAfterFin)667 TEST_F(MoqtMessageSpecificTest, DataAfterFin) {
668   MoqtParser parser(kRawQuic, visitor_);
669   parser.ProcessData(absl::string_view(), true);  // Find FIN
670   parser.ProcessData("foo", false);
671   EXPECT_TRUE(visitor_.parsing_error_.has_value());
672   EXPECT_EQ(*visitor_.parsing_error_, "Data after end of stream");
673   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kProtocolViolation);
674 }
675 
TEST_F(MoqtMessageSpecificTest,Setup2KB)676 TEST_F(MoqtMessageSpecificTest, Setup2KB) {
677   MoqtParser parser(kRawQuic, visitor_);
678   char big_message[2 * kMaxMessageHeaderSize];
679   quic::QuicDataWriter writer(sizeof(big_message), big_message);
680   writer.WriteVarInt62(static_cast<uint64_t>(MoqtMessageType::kServerSetup));
681   writer.WriteVarInt62(0x1);                    // version
682   writer.WriteVarInt62(0x1);                    // num_params
683   writer.WriteVarInt62(0xbeef);                 // unknown param
684   writer.WriteVarInt62(kMaxMessageHeaderSize);  // very long parameter
685   writer.WriteRepeatedByte(0x04, kMaxMessageHeaderSize);
686   // Send incomplete message
687   parser.ProcessData(absl::string_view(big_message, writer.length() - 1),
688                      false);
689   EXPECT_EQ(visitor_.messages_received_, 0);
690   EXPECT_TRUE(visitor_.parsing_error_.has_value());
691   EXPECT_EQ(*visitor_.parsing_error_, "Cannot parse non-OBJECT messages > 2KB");
692   EXPECT_EQ(visitor_.parsing_error_code_, MoqtError::kInternalError);
693 }
694 
TEST_F(MoqtMessageSpecificTest,UnknownMessageType)695 TEST_F(MoqtMessageSpecificTest, UnknownMessageType) {
696   MoqtParser parser(kRawQuic, visitor_);
697   char message[4];
698   quic::QuicDataWriter writer(sizeof(message), message);
699   writer.WriteVarInt62(0xbeef);  // unknown message type
700   parser.ProcessData(absl::string_view(message, writer.length()), false);
701   EXPECT_EQ(visitor_.messages_received_, 0);
702   EXPECT_TRUE(visitor_.parsing_error_.has_value());
703   EXPECT_EQ(*visitor_.parsing_error_, "Unknown message type");
704 }
705 
TEST_F(MoqtMessageSpecificTest,StartGroupIsNone)706 TEST_F(MoqtMessageSpecificTest, StartGroupIsNone) {
707   MoqtParser parser(kRawQuic, visitor_);
708   char subscribe[] = {
709       0x03, 0x01, 0x02,              // id and alias
710       0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
711       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
712       0x00,                          // start_group = none
713       0x01, 0x01,                    // start_object = 1 (absolute)
714       0x00,                          // end_group = none
715       0x00,                          // end_object = none
716       0x01,                          // 1 parameter
717       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
718   };
719   parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
720   EXPECT_EQ(visitor_.messages_received_, 0);
721   EXPECT_TRUE(visitor_.parsing_error_.has_value());
722   EXPECT_EQ(*visitor_.parsing_error_,
723             "START_GROUP must not be None in SUBSCRIBE");
724 }
725 
TEST_F(MoqtMessageSpecificTest,StartObjectIsNone)726 TEST_F(MoqtMessageSpecificTest, StartObjectIsNone) {
727   MoqtParser parser(kRawQuic, visitor_);
728   char subscribe[] = {
729       0x03, 0x01, 0x02,              // id and alias
730       0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
731       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
732       0x02, 0x04,                    // start_group = 4 (relative previous)
733       0x00,                          // start_object = none
734       0x00,                          // end_group = none
735       0x00,                          // end_object = none
736       0x01,                          // 1 parameter
737       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
738   };
739   parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
740   EXPECT_EQ(visitor_.messages_received_, 0);
741   EXPECT_TRUE(visitor_.parsing_error_.has_value());
742   EXPECT_EQ(*visitor_.parsing_error_,
743             "START_OBJECT must not be None in SUBSCRIBE");
744 }
745 
TEST_F(MoqtMessageSpecificTest,EndGroupIsNoneEndObjectIsNoNone)746 TEST_F(MoqtMessageSpecificTest, EndGroupIsNoneEndObjectIsNoNone) {
747   MoqtParser parser(kRawQuic, visitor_);
748   char subscribe[] = {
749       0x03, 0x01, 0x02,              // id and alias
750       0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
751       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
752       0x02, 0x04,                    // start_group = 4 (relative previous)
753       0x01, 0x01,                    // start_object = 1 (absolute)
754       0x00,                          // end_group = none
755       0x01, 0x01,                    // end_object = 1 (absolute)
756       0x01,                          // 1 parameter
757       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
758   };
759   parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
760   EXPECT_EQ(visitor_.messages_received_, 0);
761   EXPECT_TRUE(visitor_.parsing_error_.has_value());
762   EXPECT_EQ(*visitor_.parsing_error_,
763             "SUBSCRIBE end_group and end_object must be both None "
764             "or both non_None");
765 }
766 
TEST_F(MoqtMessageSpecificTest,AllMessagesTogether)767 TEST_F(MoqtMessageSpecificTest, AllMessagesTogether) {
768   char buffer[5000];
769   MoqtParser parser(kRawQuic, visitor_);
770   size_t write = 0;
771   size_t read = 0;
772   int fully_received = 0;
773   std::unique_ptr<TestMessageBase> prev_message = nullptr;
774   for (MoqtMessageType type : message_types) {
775     // Each iteration, process from the halfway point of one message to the
776     // halfway point of the next.
777     if (IsObjectMessage(type)) {
778       continue;  // Objects cannot share a stream with other meessages.
779     }
780     std::unique_ptr<TestMessageBase> message =
781         CreateTestMessage(type, kRawQuic);
782     memcpy(buffer + write, message->PacketSample().data(),
783            message->total_message_size());
784     size_t new_read = write + message->total_message_size() / 2;
785     parser.ProcessData(absl::string_view(buffer + read, new_read - read),
786                        false);
787     EXPECT_EQ(visitor_.messages_received_, fully_received);
788     if (prev_message != nullptr) {
789       EXPECT_TRUE(prev_message->EqualFieldValues(*visitor_.last_message_));
790     }
791     fully_received++;
792     read = new_read;
793     write += message->total_message_size();
794     prev_message = std::move(message);
795   }
796   // Deliver the rest
797   parser.ProcessData(absl::string_view(buffer + read, write - read), true);
798   EXPECT_EQ(visitor_.messages_received_, fully_received);
799   EXPECT_TRUE(prev_message->EqualFieldValues(*visitor_.last_message_));
800   EXPECT_FALSE(visitor_.parsing_error_.has_value());
801 }
802 
TEST_F(MoqtMessageSpecificTest,RelativeLocation)803 TEST_F(MoqtMessageSpecificTest, RelativeLocation) {
804   MoqtParser parser(kRawQuic, visitor_);
805   char subscribe[] = {
806       0x03, 0x01, 0x02,              // id and alias
807       0x03, 0x66, 0x6f, 0x6f,        // track_namespace = "foo"
808       0x04, 0x61, 0x62, 0x63, 0x64,  // track_name = "abcd"
809       0x02, 0x00,                    // start_group = 0 (relative previous)
810       0x03, 0x00,                    // start_object = 1 (relative next)
811       0x00,                          // end_group = none
812       0x00,                          // end_object = none
813       0x01,                          // 1 parameter
814       0x02, 0x03, 0x62, 0x61, 0x72,  // authorization_info = "bar"
815   };
816   parser.ProcessData(absl::string_view(subscribe, sizeof(subscribe)), false);
817   EXPECT_EQ(visitor_.messages_received_, 1);
818   MoqtSubscribe message = std::get<MoqtSubscribe>(*visitor_.last_message_);
819   EXPECT_FALSE(visitor_.parsing_error_.has_value());
820   ASSERT_TRUE(message.start_group.has_value());
821   ASSERT_FALSE(message.start_group->absolute);
822   EXPECT_EQ(message.start_group->relative_value, 0);
823   ASSERT_TRUE(message.start_object.has_value());
824   ASSERT_FALSE(message.start_object->absolute);
825   EXPECT_EQ(message.start_object->relative_value, 1);
826 }
827 
TEST_F(MoqtMessageSpecificTest,DatagramSuccessful)828 TEST_F(MoqtMessageSpecificTest, DatagramSuccessful) {
829   ObjectDatagramMessage message;
830   MoqtObject object;
831   absl::string_view payload =
832       MoqtParser::ProcessDatagram(message.PacketSample(), object);
833   TestMessageBase::MessageStructuredData object_metadata =
834       TestMessageBase::MessageStructuredData(object);
835   EXPECT_TRUE(message.EqualFieldValues(object_metadata));
836   EXPECT_EQ(payload, "foo");
837 }
838 
TEST_F(MoqtMessageSpecificTest,WrongMessageInDatagram)839 TEST_F(MoqtMessageSpecificTest, WrongMessageInDatagram) {
840   MoqtParser parser(kRawQuic, visitor_);
841   ObjectStreamMessage message;
842   MoqtObject object;
843   absl::string_view payload =
844       MoqtParser::ProcessDatagram(message.PacketSample(), object);
845   EXPECT_TRUE(payload.empty());
846 }
847 
TEST_F(MoqtMessageSpecificTest,TruncatedDatagram)848 TEST_F(MoqtMessageSpecificTest, TruncatedDatagram) {
849   MoqtParser parser(kRawQuic, visitor_);
850   ObjectDatagramMessage message;
851   message.set_wire_image_size(4);
852   MoqtObject object;
853   absl::string_view payload =
854       MoqtParser::ProcessDatagram(message.PacketSample(), object);
855   EXPECT_TRUE(payload.empty());
856 }
857 
TEST_F(MoqtMessageSpecificTest,VeryTruncatedDatagram)858 TEST_F(MoqtMessageSpecificTest, VeryTruncatedDatagram) {
859   MoqtParser parser(kRawQuic, visitor_);
860   char message = 0x40;
861   MoqtObject object;
862   absl::string_view payload = MoqtParser::ProcessDatagram(
863       absl::string_view(&message, sizeof(message)), object);
864   EXPECT_TRUE(payload.empty());
865 }
866 
TEST_F(MoqtMessageSpecificTest,SubscribeOkInvalidContentExists)867 TEST_F(MoqtMessageSpecificTest, SubscribeOkInvalidContentExists) {
868   MoqtParser parser(kRawQuic, visitor_);
869   SubscribeOkMessage subscribe_ok;
870   subscribe_ok.SetInvalidContentExists();
871   parser.ProcessData(subscribe_ok.PacketSample(), false);
872   EXPECT_EQ(visitor_.messages_received_, 0);
873   EXPECT_TRUE(visitor_.parsing_error_.has_value());
874   EXPECT_EQ(*visitor_.parsing_error_,
875             "SUBSCRIBE_OK ContentExists has invalid value");
876 }
877 
TEST_F(MoqtMessageSpecificTest,SubscribeDoneInvalidContentExists)878 TEST_F(MoqtMessageSpecificTest, SubscribeDoneInvalidContentExists) {
879   MoqtParser parser(kRawQuic, visitor_);
880   SubscribeDoneMessage subscribe_done;
881   subscribe_done.SetInvalidContentExists();
882   parser.ProcessData(subscribe_done.PacketSample(), false);
883   EXPECT_EQ(visitor_.messages_received_, 0);
884   EXPECT_TRUE(visitor_.parsing_error_.has_value());
885   EXPECT_EQ(*visitor_.parsing_error_,
886             "SUBSCRIBE_DONE ContentExists has invalid value");
887 }
888 
889 }  // namespace moqt::test
890