1 // Copyright 2024 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_QUIC_QUIC_SOCKET_DATA_PROVIDER_H_ 6 #define NET_QUIC_QUIC_SOCKET_DATA_PROVIDER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <optional> 11 #include <set> 12 #include <string> 13 14 #include "base/memory/weak_ptr.h" 15 #include "base/run_loop.h" 16 #include "net/quic/quic_test_packet_printer.h" 17 #include "net/socket/socket_test_util.h" 18 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h" 19 20 namespace net::test { 21 22 // A `SocketDataProvider` specifically designed to handle QUIC's packet-based 23 // nature, and to give useful errors when things do not go as planned. This 24 // fills the same purpose as `MockQuicData` and it should be straightforward to 25 // "upgrade" a use of `MockQuicData` to this class when adding or modifying 26 // tests. 27 // 28 // To use: create a new `QuicSocketDataProvider`, then add expected reads and 29 // writes to it using the `AddRead` and `AddWrite` methods. Each read or write 30 // must have a short, unique name that will appear in logs and error messages. 31 // Once the provider is populated, add it to a `MockClientSocketFactory` with 32 // `AddSocketDataProvider`. 33 // 34 // Each `Add` method creates an "expectation" that some event will occur on the 35 // socket. A write expectation signals that the system under test will call 36 // `Write` with a packet matching the given data. A read expectation signals 37 // that the SUT will call `Read`, and the data in the expectation will be 38 // returned. 39 // 40 // Expectations can be adjusted when they are created by chaining method calls, 41 // such as setting the mode. Expectations are consumed in a partial order: each 42 // expectation specifies the expectations which must be consumed before it can 43 // be consumed. By default, each expectation must come after the previously 44 // added expectation, but the `After` method can be used to adjust this ordering 45 // for cases where the order is unimportant or might vary. For example, an ACK 46 // might be written before or after a read of stream data. 47 // 48 // When a Write expectation is not met, such as write data not matching the 49 // expected packet, the Write call will result in `ERR_UNEXPECTED`. 50 // 51 // Use `--vmodule=quic_socket_data_provider*=1` in the test command-line to see 52 // additional logging from this module. 53 class QuicSocketDataProvider : public SocketDataProvider { 54 public: 55 class Expectation { 56 public: 57 enum class Type { READ, WRITE, PAUSE }; 58 59 Expectation(Expectation&) = delete; 60 Expectation& operator=(Expectation&) = delete; 61 Expectation(Expectation&&); 62 Expectation& operator=(Expectation&&); 63 ~Expectation(); 64 65 // Set the mode for this expectation, where the default is ASYNC. If a `Read 66 // or `Write` call occurs for a sync expectation when its preconditions have 67 // not been met, the test will fail. Mode(IoMode mode)68 Expectation& Mode(IoMode mode) { 69 mode_ = mode; 70 return *this; 71 } Sync()72 Expectation& Sync() { 73 Mode(SYNCHRONOUS); 74 return *this; 75 } 76 77 // Indicate that this expectation cannot be consumed until the named 78 // expectation has been consumed. 79 Expectation& After(std::string name); 80 81 // Set the TOS byte for this expectation. TosByte(uint8_t tos_byte)82 Expectation& TosByte(uint8_t tos_byte) { 83 tos_byte_ = tos_byte; 84 return *this; 85 } 86 name()87 const std::string& name() const { return name_; } type()88 Type type() const { return type_; } consumed()89 bool consumed() const { return consumed_; } after()90 const std::set<std::string>& after() const { return after_; } rv()91 int rv() const { return rv_; } packet()92 const std::unique_ptr<quic::QuicEncryptedPacket>& packet() const { 93 return packet_; 94 } mode()95 IoMode mode() const { return mode_; } tos_byte()96 uint8_t tos_byte() const { return tos_byte_; } 97 98 static std::string TypeToString(Type type); 99 100 protected: 101 friend class QuicSocketDataProvider; 102 103 Expectation(std::string name, 104 Type type, 105 int rv, 106 std::unique_ptr<quic::QuicEncryptedPacket> packet); 107 set_name(std::string name)108 void set_name(std::string name) { name_ = name; } 109 void Consume(); 110 111 private: 112 // Name for this packet, used in sequencing and logging. 113 std::string name_; 114 115 // Type of expectation. 116 Type type_; 117 118 // True when this expectation has been consumed; that is, it has been 119 // matched with a call to Read or Write and that call has returned or its 120 // callback has been called. 121 bool consumed_ = false; 122 123 // Expectations which must be consumed before this one, by name. 124 std::set<std::string> after_; 125 126 int rv_; 127 std::unique_ptr<quic::QuicEncryptedPacket> packet_; 128 IoMode mode_ = ASYNC; 129 uint8_t tos_byte_ = 0; 130 }; 131 132 // A PausePoint is just the index into the array of expectations. 133 using PausePoint = size_t; 134 135 explicit QuicSocketDataProvider(quic::ParsedQuicVersion version); 136 ~QuicSocketDataProvider() override; 137 138 // Adds a read which will result in `packet`. A reference to the provided 139 // expectation is returned, which can be used to update the settings for that 140 // expectation. The more-specific version taking `QuicReceivedPacket` also 141 // sets the TOS byte based on the packet's ECN codepoint. 142 Expectation& AddRead(std::string name, 143 std::unique_ptr<quic::QuicReceivedPacket> packet); 144 Expectation& AddRead(std::string name, 145 std::unique_ptr<quic::QuicEncryptedPacket> packet); 146 147 // Adds a read error return. A reference to the provided expectation is 148 // returned, which can be used to update the settings for that expectation. 149 Expectation& AddReadError(std::string name, int rv); 150 151 // Adds a write which will expect the given packet and return the given 152 // result. A reference to the provided packet is returned, which can be used 153 // to update the settings for the packet. 154 Expectation& AddWrite(std::string name, 155 std::unique_ptr<quic::QuicEncryptedPacket> packet, 156 int rv = OK); 157 158 // Adds a write error return. A reference to the provided expectation is 159 // returned, which can be used to update the settings for that expectation. 160 Expectation& AddWriteError(std::string name, int rv); 161 162 // Adds a Pause point, returning a handle that can be used later to wait for 163 // and resume execution. Any expectations that come "after" the pause point 164 // will not be consumed until the pause is reached and execution is resumed. 165 // 166 // Note that this is not compatible with 167 // `SequencedSocketData::RunUntilPaused()`. 168 PausePoint AddPause(std::string name); 169 170 // Checks if all data has been consumed. 171 bool AllDataConsumed() const; 172 173 // Run the main loop until the given pause point is reached. If a different 174 // pause point is reached, this will fail. Note that the results of any 175 // `Read` or `Write` calls before the pause point might not be complete, if 176 // those results were delivered asynchronously. 177 void RunUntilPause(PausePoint pause_point); 178 179 // Resumes I/O after it is paused. 180 void Resume(); 181 182 // Run the main loop until all expectations have been consumed. Note that the 183 // results of any `Read` or `Write` calls might not be complete, if those 184 // results were delivered asynchronously. 185 void RunUntilAllConsumed(); 186 187 // SocketDataProvider implementation. 188 MockRead OnRead() override; 189 MockWriteResult OnWrite(const std::string& data) override; 190 bool AllReadDataConsumed() const override; 191 bool AllWriteDataConsumed() const override; 192 void CancelPendingRead() override; 193 void Reset() override; 194 195 private: 196 // Find indexes of expectations of the given type that are ready to consume. 197 std::optional<size_t> FindReadyExpectations(Expectation::Type type); 198 199 // Find a single ready operation, if any. Fails if multiple expectations of 200 // the given type are ready. The corresponding expectation is marked as 201 // consumed, and a task is scheduled to consume any expectations that become 202 // ready as a result. 203 std::optional<MockRead> ConsumeNextRead(); 204 std::optional<MockWriteResult> ConsumeNextWrite(); 205 206 // Consume any expectations that have become ready after a change to another 207 // expectation. This is called in a task automatically after one or more calls 208 // to `ExepctationsConsumed`. 209 void MaybeConsumeExpectations(); 210 211 // Update state after an expectation has been consumed. 212 void ExpectationConsumed(); 213 214 // Verify that the packet matches `write_pending_`. 215 bool VerifyWriteData(QuicSocketDataProvider::Expectation& expectation); 216 217 // Generate a comma-separated list of expectation names. 218 std::string ExpectationList(const std::vector<size_t>& indices); 219 220 std::vector<Expectation> expectations_; 221 bool pending_maybe_consume_expectations_ = false; 222 std::map<size_t, std::set<size_t>> dependencies_; 223 bool read_pending_ = false; 224 std::optional<std::string> write_pending_ = std::nullopt; 225 QuicPacketPrinter printer_; 226 std::optional<size_t> paused_at_; 227 std::unique_ptr<base::RunLoop> run_until_run_loop_; 228 229 base::WeakPtrFactory<QuicSocketDataProvider> weak_factory_{this}; 230 }; 231 232 } // namespace net::test 233 234 #endif // NET_QUIC_QUIC_SOCKET_DATA_PROVIDER_H_ 235