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