Workaround for Android UDP network conformance test
The Android network conformance test contains a UDP test that sends an invalid QUIC packet and expects a response. The Android team wrote a fix for their test but it will take 2 months to deploy so we're adding this workaround to unblock their testing until then. The workaround is protected by quic_reply_to_old_android_conformance_test.
gfe-relnote: respond to a conformance test packet, protected by disabled flag gfe2_reloadable_flag_quic_reply_to_old_android_conformance_test
PiperOrigin-RevId: 264248926
Change-Id: I18672295da33f039f1087ad62174c598700bc47b
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index b3f13d9..d589854 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -1180,6 +1180,156 @@
destination_connection_id_bytes, sizeof(destination_connection_id_bytes));
}
+TEST_F(QuicDispatcherTest, AndroidConformanceTestOld) {
+ // TODO(b/139691956) Remove this test once the workaround is removed.
+ // This test requires the workaround behind this flag to pass.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[] = {
+ // Android UDP network conformance test packet as it was before this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0c, // public flags: 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, AndroidConformanceTestNewWithWorkaround) {
+ // TODO(b/139691956) Remove this test once the workaround is removed.
+ // This test doesn't need the workaround but we make sure that it passes even
+ // when the flag is true, also see AndroidConformanceTest below.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, true);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[1200] = {
+ // Android UDP network conformance test packet as it was after this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0d, // public flags: version, 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
+}
+
+TEST_F(QuicDispatcherTest, AndroidConformanceTest) {
+ // WARNING: do not remove or modify this test without making sure that we
+ // still have adequate coverage for the Android conformance test.
+
+ // Set the flag to false to make sure this test passes even when the
+ // workaround is disabled.
+ SetQuicReloadableFlag(quic_reply_to_old_android_conformance_test, false);
+ SavingWriter* saving_writer = new SavingWriter();
+ // dispatcher_ takes ownership of saving_writer.
+ QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer);
+
+ QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager(
+ saving_writer, dispatcher_.get(), mock_helper_.GetClock(),
+ &mock_alarm_factory_);
+ // dispatcher_ takes ownership of time_wait_list_manager.
+ QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
+ time_wait_list_manager);
+ // clang-format off
+ static const unsigned char packet[1200] = {
+ // Android UDP network conformance test packet as it was after this change:
+ // https://android-review.googlesource.com/c/platform/cts/+/1104285
+ 0x0d, // public flags: version, 8-byte connection ID, 1-byte packet number
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, // 8-byte connection ID
+ 0xaa, 0xda, 0xca, 0xaa, // reserved-space version number
+ 0x01, // 1-byte packet number
+ 0x00, // private flags
+ 0x07, // PING frame
+ };
+ // clang-format on
+
+ QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet),
+ sizeof(packet), false);
+ std::unique_ptr<QuicReceivedPacket> received_packet(
+ ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now()));
+ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0);
+
+ QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
+ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet);
+ ASSERT_EQ(1u, saving_writer->packets()->size());
+
+ // The Android UDP network conformance test directly checks that bytes 1-9
+ // of the response match the connection ID that was sent.
+ static const char connection_id_bytes[] = {0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78};
+ ASSERT_GE((*(saving_writer->packets()))[0]->length(),
+ 1u + sizeof(connection_id_bytes));
+ test::CompareCharArraysWithHexError(
+ "response connection ID", &(*(saving_writer->packets()))[0]->data()[1],
+ sizeof(connection_id_bytes), connection_id_bytes,
+ sizeof(connection_id_bytes));
+}
+
// Verify the stopgap test: Packets with truncated connection IDs should be
// dropped.
class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {};