1 #include "boost/asio/read.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/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