Add more PRIORITY_UPDATE tests.

Test that if QuicStream::SetPriority() is called with the priority that the
stream already has, then QuicSpdyStream::MaybeSendPriorityUpdateFrame() does not
send a PRIORITY_UPDATE frame.  This was prompted by automated mutation testing
commenting on cl/494755193 that removing the line
http://google3/third_party/quic/core/http/quic_spdy_stream.cc;l=595;rcl=491635277
does not cause any test failures.  Now it does.

Also add some ParsePriorityFieldValue tests to exercise code for ignoring inner
list dict values, and some tests for operator==() with out-of-bounds urgency
values.  Inspired by reviewers' comments and mutation testing findings on
cl/494755193.

Also add QuicSpdySessionTest to exercise parsing the incremental bit.  Note that
this is still unused, but at least parsed.

PiperOrigin-RevId: 495008021
diff --git a/quiche/quic/core/http/quic_spdy_session_test.cc b/quiche/quic/core/http/quic_spdy_session_test.cc
index 209b4f8..550ba80 100644
--- a/quiche/quic/core/http/quic_spdy_session_test.cc
+++ b/quiche/quic/core/http/quic_spdy_session_test.cc
@@ -2233,7 +2233,7 @@
 
   // PRIORITY_UPDATE frame for second request stream.
   const QuicStreamId stream_id2 = GetNthClientInitiatedBidirectionalId(1);
-  PriorityUpdateFrame priority_update2{stream_id2, "u=2"};
+  PriorityUpdateFrame priority_update2{stream_id2, "u=5, i"};
   std::string serialized_priority_update2 =
       HttpEncoder::SerializePriorityUpdateFrame(priority_update2);
   QuicStreamFrame stream_frame3(receive_control_stream_id,
@@ -2246,8 +2246,11 @@
   session_.OnStreamFrame(stream_frame3);
   // Priority is applied upon stream construction.
   TestStream* stream2 = session_.CreateIncomingStream(stream_id2);
-  EXPECT_EQ((QuicStreamPriority{2u, QuicStreamPriority::kDefaultIncremental}),
-            stream2->priority());
+  if (GetQuicReloadableFlag(quic_priority_update_structured_headers_parser)) {
+    EXPECT_EQ((QuicStreamPriority{5u, true}), stream2->priority());
+  } else {
+    EXPECT_EQ((QuicStreamPriority{5u, false}), stream2->priority());
+  }
 }
 
 TEST_P(QuicSpdySessionTestServer, OnInvalidPriorityUpdateFrame) {
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc
index 0325538..dbc033e 100644
--- a/quiche/quic/core/http/quic_spdy_stream_test.cc
+++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -1566,6 +1566,7 @@
   EXPECT_CALL(*stream_, WriteHeadersMock(false));
   EXPECT_CALL(debug_visitor, OnHeadersFrameSent(stream_->id(), _));
   stream_->WriteHeaders(Http2HeaderBlock(), /*fin=*/false, nullptr);
+  testing::Mock::VerifyAndClearExpectations(&debug_visitor);
 
   // PRIORITY_UPDATE frame on the control stream.
   auto send_control_stream =
@@ -1573,14 +1574,22 @@
   EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
   PriorityUpdateFrame priority_update1{stream_->id(), "u=0"};
   EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameSent(priority_update1));
-  stream_->SetPriority(QuicStreamPriority{
-      kV3HighestPriority, QuicStreamPriority::kDefaultIncremental});
+  const QuicStreamPriority priority1{kV3HighestPriority,
+                                     QuicStreamPriority::kDefaultIncremental};
+  stream_->SetPriority(priority1);
+  testing::Mock::VerifyAndClearExpectations(&debug_visitor);
 
   // Send another PRIORITY_UPDATE frame with incremental flag set to true.
   EXPECT_CALL(*session_, WritevData(send_control_stream->id(), _, _, _, _, _));
   PriorityUpdateFrame priority_update2{stream_->id(), "u=2, i"};
   EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameSent(priority_update2));
-  stream_->SetPriority(QuicStreamPriority{2, true});
+  const QuicStreamPriority priority2{2, true};
+  stream_->SetPriority(priority2);
+  testing::Mock::VerifyAndClearExpectations(&debug_visitor);
+
+  // Calling SetPriority() with the same priority does not trigger sending
+  // another PRIORITY_UPDATE frame.
+  stream_->SetPriority(priority2);
 }
 
 TEST_P(QuicSpdyStreamTest, ChangePriorityBeforeWritingHeaders) {
diff --git a/quiche/quic/core/quic_stream_priority.cc b/quiche/quic/core/quic_stream_priority.cc
index 377866a..9729706 100644
--- a/quiche/quic/core/quic_stream_priority.cc
+++ b/quiche/quic/core/quic_stream_priority.cc
@@ -57,6 +57,9 @@
     const std::vector<quiche::structured_headers::ParameterizedItem>& member =
         value.member;
     if (member.size() != 1) {
+      // If `member_is_inner_list` is false above,
+      // then `member` should have exactly one element.
+      QUICHE_BUG(priority_field_value_parsing_internal_error);
       continue;
     }
 
diff --git a/quiche/quic/core/quic_stream_priority_test.cc b/quiche/quic/core/quic_stream_priority_test.cc
index 50b6662..1ebbabb 100644
--- a/quiche/quic/core/quic_stream_priority_test.cc
+++ b/quiche/quic/core/quic_stream_priority_test.cc
@@ -21,10 +21,13 @@
                                 QuicStreamPriority::kDefaultIncremental}));
   EXPECT_EQ((QuicStreamPriority{5, true}), (QuicStreamPriority{5, true}));
   EXPECT_EQ((QuicStreamPriority{2, false}), (QuicStreamPriority{2, false}));
+  EXPECT_EQ((QuicStreamPriority{11, true}), (QuicStreamPriority{11, true}));
 
   EXPECT_NE((QuicStreamPriority{1, true}), (QuicStreamPriority{3, true}));
   EXPECT_NE((QuicStreamPriority{4, false}), (QuicStreamPriority{4, true}));
   EXPECT_NE((QuicStreamPriority{6, true}), (QuicStreamPriority{2, false}));
+  EXPECT_NE((QuicStreamPriority{12, true}), (QuicStreamPriority{9, true}));
+  EXPECT_NE((QuicStreamPriority{2, false}), (QuicStreamPriority{8, false}));
 }
 
 TEST(SerializePriorityFieldValueTest, SerializePriorityFieldValue) {
@@ -102,6 +105,12 @@
   // Cannot be parsed as structured headers.
   result = ParsePriorityFieldValue("000");
   EXPECT_FALSE(result.success);
+
+  // Inner list dictionary values are ignored.
+  result = ParsePriorityFieldValue("a=(1 2), u=1");
+  EXPECT_TRUE(result.success);
+  EXPECT_EQ(1, result.priority.urgency);
+  EXPECT_FALSE(result.priority.incremental);
 }
 
 }  // namespace quic::test