tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestHttp2WebTransport.cpp (36566B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include <utility>
      7 
      8 #include "TestCommon.h"
      9 #include "gtest/gtest.h"
     10 #include "Http2WebTransportSession.h"
     11 #include "Http2WebTransportStream.h"
     12 #include "nsString.h"
     13 #include "nsTArray.h"
     14 #include "mozilla/gtest/MozAssertions.h"
     15 #include "mozilla/Queue.h"
     16 #include "mozilla/net/NeqoHttp3Conn.h"
     17 #include "Capsule.h"
     18 #include "CapsuleEncoder.h"
     19 #include "CapsuleParser.h"
     20 #include "nsIWebTransport.h"
     21 #include "nsStreamUtils.h"
     22 #include "nsThreadUtils.h"
     23 
     24 using namespace mozilla;
     25 using namespace mozilla::net;
     26 
     27 class MockWebTransportClient : public CapsuleIOHandler {
     28 public:
     29  NS_INLINE_DECL_REFCOUNTING(MockWebTransportClient, override)
     30 
     31  explicit MockWebTransportClient(Http2WebTransportInitialSettings aSettings)
     32      : mSession(new Http2WebTransportSessionImpl(this, aSettings)),
     33        mParser(MakeUnique<CapsuleParser>(mSession)) {}
     34 
     35  Http2WebTransportSessionImpl* Session() { return mSession; }
     36 
     37  void HasCapsuleToSend() override {
     38    mSession->PrepareCapsulesToSend(mOutCapsules);
     39  }
     40 
     41  void SetSentFin() override { mSetSentFinCalled = true; }
     42 
     43  void StartReading() override { mStartReadingCalled = true; }
     44 
     45  void OnCapsuleParseFailure(nsresult aError) override {
     46    mOnParseFailureCalled = true;
     47  }
     48 
     49  void ProcessInputCapsules(
     50      mozilla::Queue<UniquePtr<CapsuleEncoder>>&& aCapsules) {
     51    while (!aCapsules.IsEmpty()) {
     52      UniquePtr<CapsuleEncoder> capsule = aCapsules.Pop();
     53      auto buffer = capsule->GetBuffer();
     54      mParser->ProcessCapsuleData(buffer.Elements(), buffer.Length());
     55    }
     56  }
     57 
     58  void ProcessOutput() {
     59    mSession->PrepareCapsulesToSend(mOutCapsules);
     60    mozilla::Queue<UniquePtr<CapsuleEncoder>> queue(std::move(mOutCapsules));
     61    while (!queue.IsEmpty()) {
     62      UniquePtr<CapsuleEncoder> encoder = queue.Pop();
     63      auto metadata = encoder->GetStreamMetadata();
     64      if (metadata) {
     65        mSession->OnStreamDataSent(StreamId(metadata->mID),
     66                                   metadata->mDataSize);
     67      }
     68      mOutCapsules.Push(std::move(encoder));
     69    }
     70  }
     71 
     72  mozilla::Queue<UniquePtr<CapsuleEncoder>> GetOutCapsules() {
     73    return std::move(mOutCapsules);
     74  }
     75 
     76  void Done() {
     77    mParser = nullptr;
     78    mSession->Close(NS_OK);
     79    mSession = nullptr;
     80  }
     81 
     82  // State tracking
     83  bool mSetSentFinCalled = false;
     84  bool mStartReadingCalled = false;
     85  bool mOnParseFailureCalled = false;
     86 
     87 private:
     88  ~MockWebTransportClient() = default;
     89 
     90  RefPtr<Http2WebTransportSessionImpl> mSession;
     91  UniquePtr<CapsuleParser> mParser;
     92  mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutCapsules;
     93 };
     94 
     95 class MockWebTransportServer : public CapsuleParser::Listener {
     96 public:
     97  NS_INLINE_DECL_REFCOUNTING(MockWebTransportServer, override)
     98 
     99  explicit MockWebTransportServer()
    100      : mParser(MakeUnique<CapsuleParser>(this)) {}
    101 
    102  bool OnCapsule(Capsule&& aCapsule) override {
    103    mReceivedCapsules.AppendElement(std::move(aCapsule));
    104    return true;
    105  }
    106  void OnCapsuleParseFailure(nsresult aError) override {
    107    MOZ_RELEASE_ASSERT(false);
    108  }
    109 
    110  nsTArray<Capsule> GetReceivedCapsules() {
    111    return std::move(mReceivedCapsules);
    112  }
    113 
    114  void ProcessInputCapsules(
    115      mozilla::Queue<UniquePtr<CapsuleEncoder>>&& aCapsules) {
    116    while (!aCapsules.IsEmpty()) {
    117      UniquePtr<CapsuleEncoder> capsule = aCapsules.Pop();
    118      auto buffer = capsule->GetBuffer();
    119      mParser->ProcessCapsuleData(buffer.Elements(), buffer.Length());
    120    }
    121  }
    122 
    123  void SendWebTransportMaxStreamsCapsule(uint64_t aLimit, bool aBidi) {
    124    Capsule capsule = Capsule::WebTransportMaxStreams(aLimit, aBidi);
    125    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    126    encoder->EncodeCapsule(capsule);
    127    mOutCapsules.Push(std::move(encoder));
    128  }
    129 
    130  void SendWebTransportStreamDataCapsule(uint64_t aID, bool aFin,
    131                                         nsTArray<uint8_t>&& aData) {
    132    Capsule capsule =
    133        Capsule::WebTransportStreamData(aID, aFin, std::move(aData));
    134    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    135    encoder->EncodeCapsule(capsule);
    136    mOutCapsules.Push(std::move(encoder));
    137  }
    138 
    139  void SendWebTransportMaxStreamDataCapsule(uint64_t aLimit, uint64_t aID) {
    140    Capsule capsule = Capsule::WebTransportMaxStreamData(aLimit, aID);
    141    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    142    encoder->EncodeCapsule(capsule);
    143    mOutCapsules.Push(std::move(encoder));
    144  }
    145 
    146  void SendWebTransportMaxDataCapsule(uint64_t aLimit) {
    147    Capsule capsule = Capsule::WebTransportMaxData(aLimit);
    148    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    149    encoder->EncodeCapsule(capsule);
    150    mOutCapsules.Push(std::move(encoder));
    151  }
    152 
    153  void SendWebTransportStopSendingCapsule(uint64_t aError, uint64_t aID) {
    154    Capsule capsule = Capsule::WebTransportStopSending(aError, aID);
    155    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    156    encoder->EncodeCapsule(capsule);
    157    mOutCapsules.Push(std::move(encoder));
    158  }
    159 
    160  void SendWebTransportResetStreamCapsule(uint64_t aError, uint64_t aSize,
    161                                          uint64_t aID) {
    162    Capsule capsule = Capsule::WebTransportResetStream(aError, aSize, aID);
    163    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    164    encoder->EncodeCapsule(capsule);
    165    mOutCapsules.Push(std::move(encoder));
    166  }
    167 
    168  void SendDatagramCapsule(nsTArray<uint8_t>&& aPayload) {
    169    Capsule capsule = Capsule::WebTransportDatagram(std::move(aPayload));
    170    UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
    171    encoder->EncodeCapsule(capsule);
    172    mOutCapsules.Push(std::move(encoder));
    173  }
    174 
    175  mozilla::Queue<UniquePtr<CapsuleEncoder>> GetOutCapsules() {
    176    return std::move(mOutCapsules);
    177  }
    178 
    179  void Done() { mParser = nullptr; }
    180 
    181 private:
    182  ~MockWebTransportServer() = default;
    183 
    184  UniquePtr<CapsuleParser> mParser;
    185  nsTArray<Capsule> mReceivedCapsules;
    186  mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutCapsules;
    187 };
    188 
    189 // TODO: will be used when testing incoming streams.
    190 class MockWebTransportSessionEventListener
    191    : public WebTransportSessionEventListener,
    192      public WebTransportSessionEventListenerInternal {
    193 public:
    194  NS_DECL_THREADSAFE_ISUPPORTS
    195  NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER
    196  NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENERINTERNAL
    197 
    198  MockWebTransportSessionEventListener() {}
    199  nsTArray<RefPtr<WebTransportStreamBase>> TakeIncomingStreams() {
    200    return std::move(mIncomingStreams);
    201  }
    202  nsTArray<uint8_t> mReceivedDatagrams;
    203 
    204  Maybe<std::pair<uint64_t, nsresult>> TakeStopSending() {
    205    return std::move(mStopSending);
    206  }
    207 
    208  Maybe<std::pair<uint64_t, nsresult>> TakeReset() { return std::move(mReset); }
    209 
    210 private:
    211  virtual ~MockWebTransportSessionEventListener() = default;
    212 
    213  nsTArray<RefPtr<WebTransportStreamBase>> mIncomingStreams;
    214  Maybe<std::pair<uint64_t, nsresult>> mStopSending;
    215  Maybe<std::pair<uint64_t, nsresult>> mReset;
    216 };
    217 
    218 NS_IMPL_ISUPPORTS(MockWebTransportSessionEventListener,
    219                  WebTransportSessionEventListener,
    220                  WebTransportSessionEventListenerInternal)
    221 
    222 NS_IMETHODIMP
    223 MockWebTransportSessionEventListener::OnSessionReadyInternal(
    224    WebTransportSessionBase* aSession) {
    225  return NS_OK;
    226 }
    227 
    228 NS_IMETHODIMP
    229 MockWebTransportSessionEventListener::OnIncomingStreamAvailableInternal(
    230    WebTransportStreamBase* aStream) {
    231  mIncomingStreams.AppendElement(RefPtr{aStream});
    232  return NS_OK;
    233 }
    234 
    235 NS_IMETHODIMP
    236 MockWebTransportSessionEventListener::OnIncomingBidirectionalStreamAvailable(
    237    nsIWebTransportBidirectionalStream* aStream) {
    238  return NS_OK;
    239 }
    240 
    241 NS_IMETHODIMP
    242 MockWebTransportSessionEventListener::OnIncomingUnidirectionalStreamAvailable(
    243    nsIWebTransportReceiveStream* aStream) {
    244  return NS_OK;
    245 }
    246 
    247 NS_IMETHODIMP
    248 MockWebTransportSessionEventListener::OnSessionReady(uint64_t ready) {
    249  return NS_OK;
    250 }
    251 
    252 NS_IMETHODIMP
    253 MockWebTransportSessionEventListener::OnSessionClosed(
    254    bool aCleanly, uint32_t aStatus, const nsACString& aReason) {
    255  return NS_OK;
    256 }
    257 
    258 NS_IMETHODIMP MockWebTransportSessionEventListener::OnDatagramReceivedInternal(
    259    nsTArray<uint8_t>&& aData) {
    260  mReceivedDatagrams = std::move(aData);
    261  return NS_OK;
    262 }
    263 
    264 NS_IMETHODIMP MockWebTransportSessionEventListener::OnDatagramReceived(
    265    const nsTArray<uint8_t>& aData) {
    266  return NS_OK;
    267 }
    268 
    269 NS_IMETHODIMP MockWebTransportSessionEventListener::OnMaxDatagramSize(
    270    uint64_t aSize) {
    271  return NS_OK;
    272 }
    273 
    274 NS_IMETHODIMP
    275 MockWebTransportSessionEventListener::OnOutgoingDatagramOutCome(
    276    uint64_t aId, WebTransportSessionEventListener::DatagramOutcome aOutCome) {
    277  return NS_OK;
    278 }
    279 
    280 NS_IMETHODIMP MockWebTransportSessionEventListener::OnStopSending(
    281    uint64_t aStreamId, nsresult aError) {
    282  mStopSending = Some(std::pair<uint64_t, nsresult>(aStreamId, aError));
    283  return NS_OK;
    284 }
    285 
    286 NS_IMETHODIMP MockWebTransportSessionEventListener::OnResetReceived(
    287    uint64_t aStreamId, nsresult aError) {
    288  mReset = Some(std::pair<uint64_t, nsresult>(aStreamId, aError));
    289  return NS_OK;
    290 }
    291 
    292 static void ServerProcessCapsules(MockWebTransportServer* aServer,
    293                                  MockWebTransportClient* aClient) {
    294  aClient->ProcessOutput();
    295  mozilla::Queue<UniquePtr<CapsuleEncoder>> outCapsules =
    296      aClient->GetOutCapsules();
    297  aServer->ProcessInputCapsules(std::move(outCapsules));
    298 }
    299 
    300 static void ClientProcessCapsules(MockWebTransportServer* aServer,
    301                                  MockWebTransportClient* aClient) {
    302  mozilla::Queue<UniquePtr<CapsuleEncoder>> outCapsules =
    303      aServer->GetOutCapsules();
    304  aClient->ProcessInputCapsules(std::move(outCapsules));
    305 }
    306 
    307 TEST(TestHttp2WebTransport, CloseSessionCapsule)
    308 {
    309  RefPtr<MockWebTransportClient> client =
    310      new MockWebTransportClient(Http2WebTransportInitialSettings());
    311  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    312 
    313  nsCString reason("test");
    314  client->Session()->CloseSession(42, "test"_ns);
    315 
    316  ServerProcessCapsules(server, client);
    317 
    318  nsTArray<Capsule> received = server->GetReceivedCapsules();
    319  ASSERT_EQ(received.Length(), 1u);
    320 
    321  CloseWebTransportSessionCapsule& parsedCapsule =
    322      received[0].GetCloseWebTransportSessionCapsule();
    323  ASSERT_EQ(parsedCapsule.mStatus, 42u);
    324  ASSERT_EQ(parsedCapsule.mReason, reason);
    325 
    326  client->Done();
    327  server->Done();
    328 }
    329 
    330 TEST(TestHttp2WebTransport, CreateOutgoingStream)
    331 {
    332  RefPtr<MockWebTransportClient> client =
    333      new MockWebTransportClient(Http2WebTransportInitialSettings());
    334  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    335 
    336  RefPtr<WebTransportStreamBase> bidiStream;
    337  auto callback =
    338      [&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
    339        if (aResult.isErr()) {
    340          return;
    341        }
    342        bidiStream = aResult.unwrap();
    343      };
    344  client->Session()->CreateOutgoingBidirectionalStream(std::move(callback));
    345  ASSERT_TRUE(bidiStream == nullptr);
    346 
    347  ServerProcessCapsules(server, client);
    348 
    349  // Creating a stream is blocked, we should see a
    350  // WebTransportStreamsBlockedCapsule from the client.
    351  nsTArray<Capsule> received = server->GetReceivedCapsules();
    352  ASSERT_EQ(received.Length(), 1u);
    353 
    354  WebTransportStreamsBlockedCapsule& streamsBlocked =
    355      received[0].GetWebTransportStreamsBlockedCapsule();
    356  ASSERT_EQ(streamsBlocked.mLimit, 0u);
    357  ASSERT_EQ(streamsBlocked.mBidi, true);
    358 
    359  server->SendWebTransportMaxStreamsCapsule(1, true);
    360  ClientProcessCapsules(server, client);
    361  ASSERT_TRUE(bidiStream != nullptr);
    362 
    363  RefPtr<WebTransportStreamBase> unidiStream;
    364  auto callback1 =
    365      [&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
    366        if (aResult.isErr()) {
    367          return;
    368        }
    369        unidiStream = aResult.unwrap();
    370      };
    371  client->Session()->CreateOutgoingUnidirectionalStream(std::move(callback1));
    372  ASSERT_TRUE(unidiStream == nullptr);
    373 
    374  ServerProcessCapsules(server, client);
    375 
    376  received = server->GetReceivedCapsules();
    377  ASSERT_EQ(received.Length(), 1u);
    378 
    379  WebTransportStreamsBlockedCapsule& streamsBlocked1 =
    380      received[0].GetWebTransportStreamsBlockedCapsule();
    381  ASSERT_EQ(streamsBlocked1.mLimit, 0u);
    382  ASSERT_EQ(streamsBlocked1.mBidi, false);
    383 
    384  server->SendWebTransportMaxStreamsCapsule(1, false);
    385  ClientProcessCapsules(server, client);
    386  ASSERT_TRUE(unidiStream != nullptr);
    387 
    388  client->Done();
    389  server->Done();
    390 }
    391 
    392 static void CreateTestData(uint32_t aNumBytes, nsTArray<uint8_t>& aDataOut) {
    393  static constexpr const char kSampleText[] =
    394      "{\"type\":\"message\",\"id\":42,\"payload\":\"The quick brown fox jumps "
    395      "over the lazy dog.\"}";
    396  static constexpr uint32_t kSampleTextLen = sizeof(kSampleText) - 1;
    397 
    398  aDataOut.SetCapacity(aNumBytes);
    399 
    400  while (aNumBytes > 0) {
    401    uint32_t chunkSize = std::min(kSampleTextLen, aNumBytes);
    402    aDataOut.AppendElements(reinterpret_cast<const uint8_t*>(kSampleText),
    403                            chunkSize);
    404    aNumBytes -= chunkSize;
    405  }
    406 }
    407 
    408 static void ValidateData(nsTArray<uint8_t>& aInput,
    409                         nsTArray<uint8_t>& aExpectedData) {
    410  ASSERT_EQ(aExpectedData.Length(), aInput.Length());
    411  for (size_t i = 0; i < aExpectedData.Length(); i++) {
    412    ASSERT_EQ(aExpectedData[i], aInput[i]);
    413  }
    414 }
    415 
    416 static void ValidateData(nsIInputStream* aStream,
    417                         nsTArray<uint8_t>& aExpectedData) {
    418  nsTArray<uint8_t> outputData;
    419  nsresult rv = NS_ConsumeStream(aStream, UINT32_MAX, outputData);
    420  ASSERT_NS_SUCCEEDED(rv);
    421  ValidateData(outputData, aExpectedData);
    422 }
    423 
    424 static std::pair<nsCOMPtr<nsIAsyncOutputStream>, nsCOMPtr<nsIAsyncInputStream>>
    425 CreateStreamAndSendData(WebTransportStreamBase* aStream,
    426                        const nsTArray<uint8_t>& aData) {
    427  nsCOMPtr<nsIAsyncOutputStream> writer;
    428  nsCOMPtr<nsIAsyncInputStream> reader;
    429  aStream->GetWriterAndReader(getter_AddRefs(writer), getter_AddRefs(reader));
    430 
    431  uint32_t numWritten = 0;
    432  (void)writer->Write((const char*)aData.Elements(), aData.Length(),
    433                      &numWritten);
    434  NS_ProcessPendingEvents(nullptr);
    435  return std::make_pair(writer, reader);
    436 }
    437 
    438 static void ValidateStreamCapsule(MockWebTransportServer* aServer,
    439                                  nsTArray<uint8_t>& aExpectedData,
    440                                  bool aExpectBidi) {
    441  nsTArray<Capsule> received = aServer->GetReceivedCapsules();
    442  ASSERT_EQ(received.Length(), 1u);
    443 
    444  WebTransportStreamDataCapsule& streamData =
    445      received[0].GetWebTransportStreamDataCapsule();
    446  StreamId id(streamData.mID);
    447  ASSERT_TRUE(id.IsClientInitiated());
    448  ASSERT_EQ(id.IsBiDi(), aExpectBidi);
    449  ValidateData(streamData.mData, aExpectedData);
    450 }
    451 
    452 static already_AddRefed<WebTransportStreamBase> CreateOutgoingStream(
    453    MockWebTransportClient* aClient, bool aBidi = true) {
    454  RefPtr<WebTransportStreamBase> stream;
    455  auto callback =
    456      [&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
    457        if (aResult.isErr()) {
    458          return;
    459        }
    460        stream = aResult.unwrap();
    461        MOZ_RELEASE_ASSERT(stream);
    462      };
    463  if (aBidi) {
    464    aClient->Session()->CreateOutgoingBidirectionalStream(std::move(callback));
    465  } else {
    466    aClient->Session()->CreateOutgoingUnidirectionalStream(std::move(callback));
    467  }
    468  return stream.forget();
    469 }
    470 
    471 TEST(TestHttp2WebTransport, OutgoingUniStream)
    472 {
    473  Http2WebTransportInitialSettings settings;
    474  settings.mInitialMaxData = 1024;
    475  settings.mInitialMaxStreamsUni = 1;
    476  settings.mInitialMaxStreamDataUni = 512;
    477  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    478  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    479 
    480  // Try to create bidi stream (should fail and trigger streams-blocked capsule)
    481  RefPtr<WebTransportStreamBase> bidiStream;
    482  client->Session()->CreateOutgoingBidirectionalStream([&](auto&& aResult) {
    483    if (aResult.isOk()) {
    484      bidiStream = aResult.unwrap();
    485    }
    486  });
    487  ASSERT_TRUE(bidiStream == nullptr);
    488 
    489  ServerProcessCapsules(server, client);
    490 
    491  {
    492    nsTArray<Capsule> received = server->GetReceivedCapsules();
    493    ASSERT_EQ(received.Length(), 1u);
    494    auto& capsule = received[0].GetWebTransportStreamsBlockedCapsule();
    495    ASSERT_EQ(capsule.mLimit, 0u);
    496    ASSERT_TRUE(capsule.mBidi);
    497  }
    498 
    499  // Create unidirectional stream and send data
    500  RefPtr<WebTransportStreamBase> unidiStream =
    501      CreateOutgoingStream(client, false);
    502  ASSERT_TRUE(unidiStream != nullptr);
    503 
    504  nsTArray<uint8_t> inputData;
    505  CreateTestData(512, inputData);
    506  CreateStreamAndSendData(unidiStream, inputData);
    507 
    508  ServerProcessCapsules(server, client);
    509  ValidateStreamCapsule(server, inputData, /* aExpectBidi = */ false);
    510 
    511  client->Done();
    512  server->Done();
    513 }
    514 
    515 TEST(TestHttp2WebTransport, OutgoingBidiStream)
    516 {
    517  Http2WebTransportInitialSettings settings;
    518  settings.mInitialMaxData = 1024;
    519  settings.mInitialMaxStreamsUni = 1;
    520  settings.mInitialMaxStreamsBidi = 1;
    521  settings.mInitialMaxStreamDataBidi = 512;
    522  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    523  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    524 
    525  RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
    526  ASSERT_TRUE(bidiStream != nullptr);
    527 
    528  nsTArray<uint8_t> inputData;
    529  CreateTestData(512, inputData);
    530  CreateStreamAndSendData(bidiStream, inputData);
    531 
    532  ServerProcessCapsules(server, client);
    533  ValidateStreamCapsule(server, inputData, /* aExpectBidi = */ true);
    534 
    535  // Echo back from server
    536  nsTArray<uint8_t> echo;
    537  echo.AppendElements(inputData.Elements(), inputData.Length());
    538  StreamId id = StreamId::From(0);
    539  server->SendWebTransportStreamDataCapsule(id, false, std::move(echo));
    540  ClientProcessCapsules(server, client);
    541 
    542  nsCOMPtr<nsIAsyncInputStream> reader;
    543  nsCOMPtr<nsIAsyncOutputStream> writer;
    544  bidiStream->GetWriterAndReader(getter_AddRefs(writer),
    545                                 getter_AddRefs(reader));
    546  uint64_t available = 0;
    547  (void)reader->Available(&available);
    548  EXPECT_EQ(available, inputData.Length());
    549 
    550  ValidateData(reader, inputData);
    551 
    552  client->Done();
    553  server->Done();
    554 }
    555 
    556 TEST(TestHttp2WebTransport, IncomingBidiStream)
    557 {
    558  Http2WebTransportInitialSettings settings;
    559  settings.mInitialLocalMaxStreamsBidi = 1;
    560  settings.mInitialLocalMaxStreamDataBidi = 512;
    561  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    562  RefPtr<MockWebTransportSessionEventListener> listener =
    563      new MockWebTransportSessionEventListener();
    564  client->Session()->SetWebTransportSessionEventListener(listener);
    565 
    566  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    567 
    568  nsTArray<uint8_t> inputData;
    569  CreateTestData(512, inputData);
    570  nsTArray<uint8_t> cloned(inputData.Clone());
    571 
    572  server->SendWebTransportStreamDataCapsule(1, false, std::move(cloned));
    573 
    574  ClientProcessCapsules(server, client);
    575 
    576  nsTArray<RefPtr<WebTransportStreamBase>> streams =
    577      listener->TakeIncomingStreams();
    578  ASSERT_EQ(streams.Length(), 1u);
    579 
    580  nsCOMPtr<nsIAsyncOutputStream> writer;
    581  nsCOMPtr<nsIAsyncInputStream> reader;
    582  RefPtr<WebTransportStreamBase> stream = streams[0];
    583  stream->GetWriterAndReader(getter_AddRefs(writer), getter_AddRefs(reader));
    584 
    585  ValidateData(reader, inputData);
    586 
    587  cloned = inputData.Clone();
    588  server->SendWebTransportStreamDataCapsule(5, false, std::move(cloned));
    589 
    590  ClientProcessCapsules(server, client);
    591  streams = listener->TakeIncomingStreams();
    592  ASSERT_EQ(streams.Length(), 0u);
    593 
    594  client->Session()->OnStreamClosed(
    595      static_cast<Http2WebTransportStream*>(stream.get()));
    596 
    597  ServerProcessCapsules(server, client);
    598 
    599  cloned = inputData.Clone();
    600  server->SendWebTransportStreamDataCapsule(5, false, std::move(cloned));
    601 
    602  ClientProcessCapsules(server, client);
    603  streams = listener->TakeIncomingStreams();
    604  ASSERT_EQ(streams.Length(), 1u);
    605 
    606  client->Done();
    607  server->Done();
    608 }
    609 
    610 TEST(TestHttp2WebTransport, StreamDataSenderFlowControl)
    611 {
    612  Http2WebTransportInitialSettings settings;
    613  settings.mInitialMaxData = 1024;
    614  settings.mInitialMaxStreamsBidi = 1;
    615  settings.mInitialMaxStreamDataBidi = 100;
    616  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    617  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    618 
    619  RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
    620  ASSERT_TRUE(bidiStream != nullptr);
    621 
    622  nsCOMPtr<nsIAsyncOutputStream> writer;
    623  nsCOMPtr<nsIAsyncInputStream> reader;
    624  bidiStream->GetWriterAndReader(getter_AddRefs(writer),
    625                                 getter_AddRefs(reader));
    626 
    627  nsTArray<uint8_t> inputData;
    628  CreateTestData(100, inputData);
    629  uint32_t numWritten = 0;
    630  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    631                      &numWritten);
    632 
    633  NS_ProcessPendingEvents(nullptr);
    634 
    635  ServerProcessCapsules(server, client);
    636 
    637  nsTArray<Capsule> received = server->GetReceivedCapsules();
    638  ASSERT_EQ(received.Length(), 1u);
    639 
    640  WebTransportStreamDataCapsule& streamData =
    641      received[0].GetWebTransportStreamDataCapsule();
    642 
    643  StreamId id(streamData.mID);
    644  ASSERT_TRUE(id.IsClientInitiated());
    645  ASSERT_TRUE(id.IsBiDi());
    646  ValidateData(streamData.mData, inputData);
    647 
    648  numWritten = 0;
    649  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    650                      &numWritten);
    651 
    652  NS_ProcessPendingEvents(nullptr);
    653  ServerProcessCapsules(server, client);
    654 
    655  received = server->GetReceivedCapsules();
    656  ASSERT_EQ(received.Length(), 1u);
    657 
    658  WebTransportStreamDataBlockedCapsule& blocked =
    659      received[0].GetWebTransportStreamDataBlockedCapsule();
    660  StreamId receivedId(blocked.mID);
    661  ASSERT_EQ(id, receivedId);
    662  ASSERT_EQ(blocked.mLimit, 100u);
    663 
    664  server->SendWebTransportMaxStreamDataCapsule(300, id);
    665  ClientProcessCapsules(server, client);
    666 
    667  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    668                      &numWritten);
    669 
    670  NS_ProcessPendingEvents(nullptr);
    671  ServerProcessCapsules(server, client);
    672 
    673  received = server->GetReceivedCapsules();
    674  ASSERT_EQ(received.Length(), 1u);
    675 
    676  WebTransportStreamDataCapsule& streamData1 =
    677      received[0].GetWebTransportStreamDataCapsule();
    678  ASSERT_EQ(streamData1.mData.Length(), 200u);
    679 
    680  client->Done();
    681  server->Done();
    682 }
    683 
    684 TEST(TestHttp2WebTransport, StreamDataSenderFlowControlMaxData)
    685 {
    686  Http2WebTransportInitialSettings settings;
    687  settings.mInitialMaxData = 100;
    688  settings.mInitialMaxStreamsBidi = 1;
    689  settings.mInitialMaxStreamDataBidi = 100;
    690  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    691  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    692 
    693  RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
    694  ASSERT_TRUE(bidiStream != nullptr);
    695 
    696  nsCOMPtr<nsIAsyncOutputStream> writer;
    697  nsCOMPtr<nsIAsyncInputStream> reader;
    698  bidiStream->GetWriterAndReader(getter_AddRefs(writer),
    699                                 getter_AddRefs(reader));
    700 
    701  nsTArray<uint8_t> inputData;
    702  CreateTestData(100, inputData);
    703  uint32_t numWritten = 0;
    704  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    705                      &numWritten);
    706 
    707  NS_ProcessPendingEvents(nullptr);
    708 
    709  ServerProcessCapsules(server, client);
    710 
    711  nsTArray<Capsule> received = server->GetReceivedCapsules();
    712  ASSERT_EQ(received.Length(), 1u);
    713 
    714  WebTransportStreamDataCapsule& streamData =
    715      received[0].GetWebTransportStreamDataCapsule();
    716 
    717  StreamId id(streamData.mID);
    718  ASSERT_TRUE(id.IsClientInitiated());
    719  ASSERT_TRUE(id.IsBiDi());
    720  ValidateData(streamData.mData, inputData);
    721 
    722  numWritten = 0;
    723  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    724                      &numWritten);
    725 
    726  NS_ProcessPendingEvents(nullptr);
    727  ServerProcessCapsules(server, client);
    728 
    729  received = server->GetReceivedCapsules();
    730  ASSERT_EQ(received.Length(), 2u);
    731 
    732  WebTransportDataBlockedCapsule& sessionDataBlocked =
    733      received[0].GetWebTransportDataBlockedCapsule();
    734  ASSERT_EQ(sessionDataBlocked.mLimit, 100u);
    735 
    736  WebTransportStreamDataBlockedCapsule& blocked =
    737      received[1].GetWebTransportStreamDataBlockedCapsule();
    738  StreamId receivedId(blocked.mID);
    739  ASSERT_EQ(id, receivedId);
    740  ASSERT_EQ(blocked.mLimit, 100u);
    741 
    742  server->SendWebTransportMaxStreamDataCapsule(500, id);
    743  ClientProcessCapsules(server, client);
    744 
    745  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    746                      &numWritten);
    747 
    748  NS_ProcessPendingEvents(nullptr);
    749  ServerProcessCapsules(server, client);
    750 
    751  received = server->GetReceivedCapsules();
    752  ASSERT_EQ(received.Length(), 0u);
    753 
    754  server->SendWebTransportMaxDataCapsule(1024);
    755  ClientProcessCapsules(server, client);
    756 
    757  (void)writer->Write((const char*)inputData.Elements(), inputData.Length(),
    758                      &numWritten);
    759 
    760  NS_ProcessPendingEvents(nullptr);
    761  ServerProcessCapsules(server, client);
    762 
    763  received = server->GetReceivedCapsules();
    764  ASSERT_EQ(received.Length(), 1u);
    765 
    766  WebTransportStreamDataCapsule& streamData1 =
    767      received[0].GetWebTransportStreamDataCapsule();
    768  ASSERT_EQ(streamData1.mData.Length(), 300u);
    769 
    770  client->Done();
    771  server->Done();
    772 }
    773 
    774 static void CheckFc(ReceiverFlowControlBase& aFc, uint64_t aConsumed,
    775                    uint64_t aRetired) {
    776  MOZ_RELEASE_ASSERT(aFc.Consumed() == aConsumed);
    777  MOZ_RELEASE_ASSERT(aFc.Retired() == aRetired);
    778 }
    779 
    780 TEST(TestHttp2WebTransport, ReceiverFlowControl)
    781 {
    782  const uint32_t FC_SIZE = 1024;
    783  Http2WebTransportInitialSettings settings;
    784  settings.mInitialMaxStreamsBidi = 2;
    785  settings.mInitialLocalMaxStreamDataBidi = FC_SIZE * 3 / 4;
    786  settings.mInitialLocalMaxData = FC_SIZE;
    787  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    788  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    789 
    790  RefPtr<WebTransportStreamBase> s1 = CreateOutgoingStream(client);
    791  ASSERT_TRUE(s1 != nullptr);
    792 
    793  RefPtr<WebTransportStreamBase> s2 = CreateOutgoingStream(client);
    794  ASSERT_TRUE(s2 != nullptr);
    795 
    796  CheckFc(client->Session()->ReceiverFc(), 0, 0);
    797  CheckFc(*s1->ReceiverFc(), 0, 0);
    798  CheckFc(*s2->ReceiverFc(), 0, 0);
    799 
    800  nsTArray<uint8_t> inputData;
    801  CreateTestData(FC_SIZE / 4, inputData);
    802 
    803  StreamId id = StreamId::From(0);
    804  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    805 
    806  CreateTestData(FC_SIZE / 4, inputData);
    807  StreamId id1 = StreamId::From(4);
    808  server->SendWebTransportStreamDataCapsule(id1, false, std::move(inputData));
    809 
    810  ClientProcessCapsules(server, client);
    811 
    812  CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
    813  CheckFc(*s1->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
    814  CheckFc(*s2->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
    815 
    816  CreateTestData(FC_SIZE / 4, inputData);
    817  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    818 
    819  ClientProcessCapsules(server, client);
    820 
    821  CheckFc(client->Session()->ReceiverFc(), FC_SIZE * 3 / 4, FC_SIZE * 3 / 4);
    822  CheckFc(*s1->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
    823  CheckFc(*s2->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
    824 
    825  client->Done();
    826  server->Done();
    827 }
    828 
    829 TEST(TestHttp2WebTransport, ReceiverFlowControl1)
    830 {
    831  const uint32_t FC_SIZE = 1024;
    832  Http2WebTransportInitialSettings settings;
    833  settings.mInitialMaxStreamsBidi = 1;
    834  settings.mInitialLocalMaxStreamDataBidi = FC_SIZE / 2;
    835  settings.mInitialLocalMaxData = FC_SIZE;
    836  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    837  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    838 
    839  RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
    840  ASSERT_TRUE(bidiStream != nullptr);
    841 
    842  nsCOMPtr<nsIAsyncOutputStream> writer;
    843  nsCOMPtr<nsIAsyncInputStream> reader;
    844  bidiStream->GetWriterAndReader(getter_AddRefs(writer),
    845                                 getter_AddRefs(reader));
    846 
    847  nsTArray<uint8_t> inputData;
    848  CreateTestData(FC_SIZE / 4, inputData);
    849 
    850  StreamId id = StreamId::From(0);
    851  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    852  ClientProcessCapsules(server, client);
    853 
    854  uint64_t available = 0;
    855  (void)reader->Available(&available);
    856  EXPECT_EQ(available, FC_SIZE / 4);
    857 
    858  nsTArray<uint8_t> outputData;
    859  nsresult rv = NS_ConsumeStream(reader, UINT32_MAX, outputData);
    860  ASSERT_NS_SUCCEEDED(rv);
    861 
    862  CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
    863  CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
    864 
    865  CreateTestData(1, inputData);
    866  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    867  ClientProcessCapsules(server, client);
    868 
    869  CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 4 + 1, FC_SIZE / 4 + 1);
    870  CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 4 + 1, FC_SIZE / 4 + 1);
    871 
    872  available = 0;
    873  (void)reader->Available(&available);
    874  EXPECT_EQ(available, 1u);
    875 
    876  ServerProcessCapsules(server, client);
    877 
    878  nsTArray<Capsule> received = server->GetReceivedCapsules();
    879  ASSERT_EQ(received.Length(), 1u);
    880 
    881  WebTransportMaxStreamDataCapsule& capsule =
    882      received[0].GetWebTransportMaxStreamDataCapsule();
    883  ASSERT_EQ(capsule.mID, 0u);
    884  ASSERT_EQ(capsule.mLimit, FC_SIZE * 3 / 4 + 1);
    885 
    886  CreateTestData(FC_SIZE / 4 - 1, inputData);
    887  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    888  ClientProcessCapsules(server, client);
    889 
    890  CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
    891  CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
    892 
    893  CreateTestData(1, inputData);
    894  server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
    895  ClientProcessCapsules(server, client);
    896 
    897  CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2 + 1, FC_SIZE / 2 + 1);
    898  CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 2 + 1, FC_SIZE / 2 + 1);
    899 
    900  ServerProcessCapsules(server, client);
    901  received = server->GetReceivedCapsules();
    902  ASSERT_EQ(received.Length(), 1u);
    903 
    904  WebTransportMaxDataCapsule& maxData =
    905      received[0].GetWebTransportMaxDataCapsule();
    906  ASSERT_EQ(maxData.mMaxDataSize, FC_SIZE * 3 / 2 + 1);
    907 
    908  client->Done();
    909  server->Done();
    910 }
    911 
    912 TEST(TestHttp2WebTransport, StreamStopSending)
    913 {
    914  Http2WebTransportInitialSettings settings;
    915  settings.mInitialMaxStreamsUni = 1;
    916  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    917  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    918 
    919  RefPtr<WebTransportStreamBase> uniStream =
    920      CreateOutgoingStream(client, false);
    921  ASSERT_TRUE(uniStream != nullptr);
    922 
    923  uniStream->SendStopSending(0);
    924  ServerProcessCapsules(server, client);
    925 
    926  nsTArray<Capsule> received = server->GetReceivedCapsules();
    927  ASSERT_EQ(received.Length(), 1u);
    928 
    929  WebTransportStopSendingCapsule& stopSending =
    930      received[0].GetWebTransportStopSendingCapsule();
    931  ASSERT_EQ(stopSending.mID, uniStream->WebTransportStreamId());
    932  ASSERT_EQ(stopSending.mErrorCode, 0u);
    933 
    934  client->Done();
    935  server->Done();
    936 }
    937 
    938 TEST(TestHttp2WebTransport, StreamOnStopSending)
    939 {
    940  Http2WebTransportInitialSettings settings;
    941  settings.mInitialMaxStreamsUni = 1;
    942  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    943  RefPtr<MockWebTransportSessionEventListener> listener =
    944      new MockWebTransportSessionEventListener();
    945  client->Session()->SetWebTransportSessionEventListener(listener);
    946  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    947 
    948  RefPtr<WebTransportStreamBase> uniStream =
    949      CreateOutgoingStream(client, false);
    950  ASSERT_TRUE(uniStream != nullptr);
    951 
    952  nsTArray<uint8_t> inputData;
    953  CreateTestData(512, inputData);
    954  CreateStreamAndSendData(uniStream, inputData);
    955 
    956  ServerProcessCapsules(server, client);
    957 
    958  server->SendWebTransportStopSendingCapsule(0,
    959                                             uniStream->WebTransportStreamId());
    960  ClientProcessCapsules(server, client);
    961 
    962  auto stopSending = listener->TakeStopSending();
    963  ASSERT_TRUE(stopSending);
    964  ASSERT_EQ(stopSending->first, uniStream->WebTransportStreamId());
    965  ASSERT_EQ(stopSending->second, NS_ERROR_WEBTRANSPORT_CODE_BASE);
    966 
    967  client->Done();
    968  server->Done();
    969 }
    970 
    971 TEST(TestHttp2WebTransport, StreamReset)
    972 {
    973  const uint32_t TOTAL_SIZE = 1024;
    974  Http2WebTransportInitialSettings settings;
    975  settings.mInitialMaxStreamsBidi = 1;
    976  settings.mInitialMaxStreamDataBidi = TOTAL_SIZE;
    977  settings.mInitialMaxData = TOTAL_SIZE;
    978  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
    979  RefPtr<MockWebTransportSessionEventListener> listener =
    980      new MockWebTransportSessionEventListener();
    981  client->Session()->SetWebTransportSessionEventListener(listener);
    982  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
    983 
    984  RefPtr<WebTransportStreamBase> stream = CreateOutgoingStream(client);
    985  ASSERT_TRUE(stream != nullptr);
    986 
    987  nsTArray<uint8_t> inputData;
    988  CreateTestData(TOTAL_SIZE / 4, inputData);
    989  CreateStreamAndSendData(stream, inputData);
    990 
    991  ServerProcessCapsules(server, client);
    992 
    993  inputData.Clear();
    994  CreateTestData(TOTAL_SIZE / 4, inputData);
    995  CreateStreamAndSendData(stream, inputData);
    996 
    997  ServerProcessCapsules(server, client);
    998 
    999  nsTArray<Capsule> received = server->GetReceivedCapsules();
   1000  ASSERT_EQ(received.Length(), 2u);
   1001 
   1002  stream->Reset(0);
   1003 
   1004  ServerProcessCapsules(server, client);
   1005  received = server->GetReceivedCapsules();
   1006  ASSERT_EQ(received.Length(), 1u);
   1007 
   1008  WebTransportResetStreamCapsule& reset =
   1009      received[0].GetWebTransportResetStreamCapsule();
   1010  ASSERT_EQ(reset.mID, stream->WebTransportStreamId());
   1011  ASSERT_EQ(reset.mErrorCode, 0u);
   1012  ASSERT_EQ(reset.mReliableSize, TOTAL_SIZE / 2);
   1013 
   1014  client->Done();
   1015  server->Done();
   1016 }
   1017 
   1018 TEST(TestHttp2WebTransport, StreamResetReliableSize)
   1019 {
   1020  const uint32_t TOTAL_SIZE = 1024;
   1021  Http2WebTransportInitialSettings settings;
   1022  settings.mInitialMaxStreamsBidi = 1;
   1023  settings.mInitialMaxStreamDataBidi = TOTAL_SIZE;
   1024  settings.mInitialMaxData = TOTAL_SIZE;
   1025  RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
   1026  RefPtr<MockWebTransportSessionEventListener> listener =
   1027      new MockWebTransportSessionEventListener();
   1028  client->Session()->SetWebTransportSessionEventListener(listener);
   1029  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
   1030 
   1031  RefPtr<WebTransportStreamBase> stream = CreateOutgoingStream(client);
   1032  ASSERT_TRUE(stream != nullptr);
   1033 
   1034  nsTArray<uint8_t> inputData;
   1035  CreateTestData(TOTAL_SIZE / 4, inputData);
   1036  auto streams = CreateStreamAndSendData(stream, inputData);
   1037 
   1038  ServerProcessCapsules(server, client);
   1039 
   1040  server->SendWebTransportStreamDataCapsule(stream->WebTransportStreamId(),
   1041                                            false, std::move(inputData));
   1042  CreateTestData(TOTAL_SIZE / 4, inputData);
   1043  server->SendWebTransportStreamDataCapsule(stream->WebTransportStreamId(),
   1044                                            false, std::move(inputData));
   1045 
   1046  server->SendWebTransportResetStreamCapsule(0, TOTAL_SIZE / 2,
   1047                                             stream->WebTransportStreamId());
   1048  ClientProcessCapsules(server, client);
   1049 
   1050  auto reset = listener->TakeReset();
   1051  ASSERT_TRUE(reset);
   1052  ASSERT_EQ(reset->first, stream->WebTransportStreamId());
   1053  ASSERT_EQ(reset->second, NS_ERROR_WEBTRANSPORT_CODE_BASE);
   1054 
   1055  client->Done();
   1056  server->Done();
   1057 }
   1058 
   1059 TEST(TestHttp2WebTransport, SendAndReceiveDatagram)
   1060 {
   1061  RefPtr<MockWebTransportClient> client =
   1062      new MockWebTransportClient(Http2WebTransportInitialSettings());
   1063  RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
   1064  RefPtr<MockWebTransportSessionEventListener> listener =
   1065      new MockWebTransportSessionEventListener();
   1066  client->Session()->SetWebTransportSessionEventListener(listener);
   1067 
   1068  nsTArray<uint8_t> mockData, expectedData;
   1069  CreateTestData(512, mockData);
   1070  expectedData.AppendElements(mockData);
   1071 
   1072  // Send datagram from client to server
   1073  client->Session()->SendDatagram(std::move(mockData), 1);
   1074  ServerProcessCapsules(server, client);
   1075 
   1076  // Verify the server received the correct datagram capsule
   1077  nsTArray<Capsule> received = server->GetReceivedCapsules();
   1078  WebTransportDatagramCapsule& parsedCapsule =
   1079      received[0].GetWebTransportDatagramCapsule();
   1080  ValidateData(parsedCapsule.mPayload, expectedData);
   1081 
   1082  // Echo and verify the received datagram payload back to the client
   1083  server->SendDatagramCapsule(std::move(parsedCapsule.mPayload));
   1084  ClientProcessCapsules(server, client);
   1085  ValidateData(listener->mReceivedDatagrams, expectedData);
   1086 
   1087  client->Done();
   1088  server->Done();
   1089 }