xref: /openbmc/bmcweb/test/http/server_sent_event_test.cpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include "http/server_sent_event.hpp"
4 #include "http_request.hpp"
5 
6 #include <boost/asio/buffer.hpp>
7 #include <boost/asio/io_context.hpp>
8 #include <boost/asio/read.hpp>
9 #include <boost/beast/_experimental/test/stream.hpp>
10 
11 #include <chrono>
12 #include <memory>
13 #include <string>
14 #include <string_view>
15 #include <utility>
16 
17 #include "gtest/gtest.h"
18 namespace crow
19 {
20 namespace sse_socket
21 {
22 
23 namespace
24 {
25 
TEST(ServerSentEvent,SseWorks)26 TEST(ServerSentEvent, SseWorks)
27 {
28     boost::asio::io_context io;
29     boost::beast::test::stream stream(io);
30     boost::beast::test::stream out(io);
31     stream.connect(out);
32 
33     Request req;
34 
35     bool openCalled = false;
36     auto openHandler =
37         [&openCalled](Connection&, const Request& /*handedReq*/) {
38             openCalled = true;
39         };
40     bool closeCalled = false;
41     auto closeHandler = [&closeCalled](Connection&) { closeCalled = true; };
42 
43     std::shared_ptr<ConnectionImpl<boost::beast::test::stream>> conn =
44         std::make_shared<ConnectionImpl<boost::beast::test::stream>>(
45             std::move(stream), openHandler, closeHandler);
46     conn->start(req);
47     // Connect
48     {
49         constexpr std::string_view expected =
50             "HTTP/1.1 200 OK\r\n"
51             "Content-Type: text/event-stream\r\n"
52             "\r\n";
53 
54         while (out.str().size() != expected.size() || !openCalled)
55         {
56             io.run_for(std::chrono::milliseconds(1));
57         }
58 
59         std::string eventContent;
60         eventContent.resize(expected.size());
61         boost::asio::read(out, boost::asio::buffer(eventContent));
62 
63         EXPECT_EQ(eventContent, expected);
64         EXPECT_TRUE(openCalled);
65         EXPECT_FALSE(closeCalled);
66         EXPECT_TRUE(out.str().empty());
67     }
68     // Send one event
69     {
70         conn->sendSseEvent("TestEventId", "TestEventContent");
71         std::string_view expected = "id: TestEventId\n"
72                                     "data: TestEventContent\n"
73                                     "\n";
74 
75         while (out.str().size() < expected.size())
76         {
77             io.run_for(std::chrono::milliseconds(1));
78         }
79         EXPECT_EQ(out.str(), expected);
80 
81         std::string eventContent;
82         eventContent.resize(expected.size());
83         boost::asio::read(out, boost::asio::buffer(eventContent));
84 
85         EXPECT_EQ(eventContent, expected);
86         EXPECT_TRUE(out.str().empty());
87     }
88     // Send second event
89     {
90         conn->sendSseEvent("TestEventId2", "TestEvent\nContent2");
91         constexpr std::string_view expected =
92             "id: TestEventId2\n"
93             "data: TestEvent\n"
94             "data: Content2\n"
95             "\n";
96 
97         while (out.str().size() < expected.size())
98         {
99             io.run_for(std::chrono::milliseconds(1));
100         }
101 
102         std::string eventContent;
103         eventContent.resize(expected.size());
104         boost::asio::read(out, boost::asio::buffer(eventContent));
105         EXPECT_EQ(eventContent, expected);
106         EXPECT_TRUE(out.str().empty());
107     }
108     // close the remote
109     {
110         out.close();
111         while (!closeCalled)
112         {
113             io.run_for(std::chrono::milliseconds(1));
114         }
115     }
116 }
117 } // namespace
118 
119 } // namespace sse_socket
120 } // namespace crow
121