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 Request req; 32 33 bool openCalled = false; 34 auto openHandler = 35 [&openCalled](Connection&, const Request& /*handedReq*/) { 36 openCalled = true; 37 }; 38 bool closeCalled = false; 39 auto closeHandler = [&closeCalled](Connection&) { closeCalled = true; }; 40 41 std::shared_ptr<ConnectionImpl<boost::beast::test::stream>> conn = 42 std::make_shared<ConnectionImpl<boost::beast::test::stream>>( 43 std::move(stream), openHandler, closeHandler); 44 conn->start(req); 45 // Connect 46 { 47 constexpr std::string_view expected = 48 "HTTP/1.1 200 OK\r\n" 49 "Content-Type: text/event-stream\r\n" 50 "\r\n"; 51 52 while (out.str().size() != expected.size()) 53 { 54 io.run_for(std::chrono::milliseconds(1)); 55 } 56 57 std::string eventContent; 58 eventContent.resize(expected.size()); 59 boost::asio::read(out, boost::asio::buffer(eventContent)); 60 61 EXPECT_EQ(eventContent, expected); 62 EXPECT_TRUE(openCalled); 63 EXPECT_FALSE(closeCalled); 64 EXPECT_TRUE(out.str().empty()); 65 } 66 // Send one event 67 { 68 conn->sendEvent("TestEventId", "TestEventContent"); 69 std::string_view expected = "id: TestEventId\n" 70 "data: TestEventContent\n" 71 "\n"; 72 73 while (out.str().size() < expected.size()) 74 { 75 io.run_for(std::chrono::milliseconds(1)); 76 } 77 EXPECT_EQ(out.str(), expected); 78 79 std::string eventContent; 80 eventContent.resize(expected.size()); 81 boost::asio::read(out, boost::asio::buffer(eventContent)); 82 83 EXPECT_EQ(eventContent, expected); 84 EXPECT_TRUE(out.str().empty()); 85 } 86 // Send second event 87 { 88 conn->sendEvent("TestEventId2", "TestEvent\nContent2"); 89 constexpr std::string_view expected = 90 "id: TestEventId2\n" 91 "data: TestEvent\n" 92 "data: Content2\n" 93 "\n"; 94 95 while (out.str().size() < expected.size()) 96 { 97 io.run_for(std::chrono::milliseconds(1)); 98 } 99 100 std::string eventContent; 101 eventContent.resize(expected.size()); 102 boost::asio::read(out, boost::asio::buffer(eventContent)); 103 EXPECT_EQ(eventContent, expected); 104 EXPECT_TRUE(out.str().empty()); 105 } 106 // close the remote 107 { 108 out.close(); 109 while (!closeCalled) 110 { 111 io.run_for(std::chrono::milliseconds(1)); 112 } 113 } 114 } 115 } // namespace 116 117 } // namespace sse_socket 118 } // namespace crow 119