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