xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/moqt/tools/moqt_end_to_end_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 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 // End-to-end test for MoqtClient/MoqtServer.
6 //
7 // IMPORTANT NOTE:
8 // This test mostly exists to test the two classes mentioned above. When
9 // possible, moqt_integration_test should be used instead, as it does not use
10 // real clocks or I/O and thus has less overhead.
11 
12 #include <memory>
13 #include <string>
14 #include <utility>
15 
16 #include "absl/functional/bind_front.h"
17 #include "absl/status/status.h"
18 #include "absl/status/statusor.h"
19 #include "absl/strings/string_view.h"
20 #include "quiche/quic/core/io/quic_event_loop.h"
21 #include "quiche/quic/core/quic_server_id.h"
22 #include "quiche/quic/moqt/moqt_session.h"
23 #include "quiche/quic/moqt/tools/moqt_client.h"
24 #include "quiche/quic/moqt/tools/moqt_server.h"
25 #include "quiche/quic/platform/api/quic_ip_address.h"
26 #include "quiche/quic/platform/api/quic_socket_address.h"
27 #include "quiche/quic/platform/api/quic_test_loopback.h"
28 #include "quiche/quic/test_tools/crypto_test_utils.h"
29 #include "quiche/quic/tools/quic_event_loop_tools.h"
30 #include "quiche/common/platform/api/quiche_logging.h"
31 #include "quiche/common/platform/api/quiche_test.h"
32 #include "quiche/common/quiche_callbacks.h"
33 
34 namespace moqt::test {
35 namespace {
36 
37 constexpr absl::string_view kNotFoundPath = "/not-found";
38 
UnexpectedClose(absl::string_view reason)39 void UnexpectedClose(absl::string_view reason) {
40   ADD_FAILURE() << "Unexpected close of MoQT session with reason: " << reason;
41 }
42 
43 class MoqtEndToEndTest : public quiche::test::QuicheTest {
44  public:
MoqtEndToEndTest()45   MoqtEndToEndTest()
46       : server_(quic::test::crypto_test_utils::ProofSourceForTesting(),
47                 absl::bind_front(&MoqtEndToEndTest::ServerBackend, this)) {
48     quic::QuicIpAddress host = quic::TestLoopback();
49     bool success = server_.quic_server().CreateUDPSocketAndListen(
50         quic::QuicSocketAddress(host, /*port=*/0));
51     QUICHE_CHECK(success);
52     server_address_ =
53         quic::QuicSocketAddress(host, server_.quic_server().port());
54     event_loop_ = server_.quic_server().event_loop();
55   }
56 
ServerBackend(absl::string_view path)57   absl::StatusOr<MoqtConfigureSessionCallback> ServerBackend(
58       absl::string_view path) {
59     QUICHE_LOG(INFO) << "Server: Received a request for path " << path;
60     if (path == kNotFoundPath) {
61       return absl::NotFoundError("404 test endpoint");
62     }
63     return [](MoqtSession* session) {
64       session->callbacks().session_established_callback = []() {
65         QUICHE_LOG(INFO) << "Server: session established";
66       };
67       session->callbacks().session_terminated_callback =
68           [](absl::string_view reason) {
69             QUICHE_LOG(INFO)
70                 << "Server: session terminated with reason: " << reason;
71           };
72     };
73   }
74 
CreateClient()75   std::unique_ptr<MoqtClient> CreateClient() {
76     return std::make_unique<MoqtClient>(
77         server_address_, quic::QuicServerId("test.example.com", 443),
78         quic::test::crypto_test_utils::ProofVerifierForTesting(), event_loop_);
79   }
80 
RunEventsUntil(quiche::UnretainedCallback<bool ()> callback)81   bool RunEventsUntil(quiche::UnretainedCallback<bool()> callback) {
82     return quic::ProcessEventsUntil(event_loop_, callback);
83   }
84 
85  private:
86   MoqtServer server_;
87   quic::QuicEventLoop* event_loop_;
88   quic::QuicSocketAddress server_address_;
89 };
90 
TEST_F(MoqtEndToEndTest,SuccessfulHandshake)91 TEST_F(MoqtEndToEndTest, SuccessfulHandshake) {
92   MoqtSessionCallbacks callbacks;
93   bool established = false;
94   bool deleted = false;
95   callbacks.session_established_callback = [&] { established = true; };
96   callbacks.session_terminated_callback = UnexpectedClose;
97   callbacks.session_deleted_callback = [&] { deleted = true; };
98   std::unique_ptr<MoqtClient> client = CreateClient();
99   client->Connect("/test", std::move(callbacks));
100   bool success = RunEventsUntil([&] { return established; });
101   EXPECT_TRUE(success);
102   EXPECT_FALSE(deleted);
103   client.reset();
104   EXPECT_TRUE(deleted);
105 }
106 
TEST_F(MoqtEndToEndTest,HandshakeFailed404)107 TEST_F(MoqtEndToEndTest, HandshakeFailed404) {
108   MoqtSessionCallbacks callbacks;
109   bool resolved = false;
110   callbacks.session_established_callback = [&] {
111     ADD_FAILURE() << "Established session when 404 expected";
112     resolved = true;
113   };
114   callbacks.session_terminated_callback = [&](absl::string_view error) {
115     resolved = true;
116   };
117   std::unique_ptr<MoqtClient> client = CreateClient();
118   client->Connect(std::string(kNotFoundPath), std::move(callbacks));
119   bool success = RunEventsUntil([&] { return resolved; });
120   EXPECT_TRUE(success);
121 }
122 
123 }  // namespace
124 }  // namespace moqt::test
125