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