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