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