From b5f288d294e17719f30e32acc40e07681baf04b9 Mon Sep 17 00:00:00 2001 From: Abhilash Raju Date: Wed, 8 Nov 2023 22:32:44 -0600 Subject: Make use of filebody for dump offload Logservice has been rewritten to use file_body to offload dump files from BMC. There are two kind of dump files, BMC dump and System dump.While BMC dump just requires default support from beast::file_body, System dump requires base64 encoding support from beast. But beast::file_body do not have ready-made support for base64 encoding. So a custom file_body has been written for the base64 encoding. The openFile apis in crow::Response do not have support for unix file descriptor. Since dump files are accesses via descriptors, added new openFile api that accepts descriptors. Tested: Functionality test have been executed to verify the bmc dump offload. Did sanity test by invoking bmcweb pages via browser. Change-Id: I24192657c03d8b2f0394d31e7424c6796ba3227a Signed-off-by: Abhilash Raju --- test/http/http_response_test.cpp | 156 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/http/http_response_test.cpp b/test/http/http_response_test.cpp index c644ea9c05..1ee3853f78 100644 --- a/test/http/http_response_test.cpp +++ b/test/http/http_response_test.cpp @@ -22,17 +22,76 @@ void verifyHeaders(crow::Response& res) EXPECT_EQ(res.result(), boost::beast::http::status::ok); } -std::string makeFile() +std::string makeFile(std::string_view sampleData) { std::filesystem::path path = std::filesystem::temp_directory_path(); path /= "bmcweb_http_response_test_XXXXXXXXXXX"; std::string stringPath = path.string(); int fd = mkstemp(stringPath.data()); EXPECT_GT(fd, 0); - std::string_view sample = "sample text"; - EXPECT_EQ(write(fd, sample.data(), sample.size()), sample.size()); + EXPECT_EQ(write(fd, sampleData.data(), sampleData.size()), + sampleData.size()); + close(fd); return stringPath; } + +void readHeader(boost::beast::http::serializer& sr) +{ + while (!sr.is_header_done()) + { + boost::system::error_code ec; + sr.next(ec, [&sr](const boost::system::error_code& ec2, + const auto& buffer) { + ASSERT_FALSE(ec2); + sr.consume(boost::beast::buffer_bytes(buffer)); + }); + ASSERT_FALSE(ec); + } +} + +std::string collectFromBuffers( + const auto& buffer, + boost::beast::http::serializer& sr) +{ + std::string ret; + + for (auto iter = boost::asio::buffer_sequence_begin(buffer); + iter != boost::asio::buffer_sequence_end(buffer); ++iter) + { + const auto& innerBuf = *iter; + auto view = std::string_view(static_cast(innerBuf.data()), + innerBuf.size()); + ret += view; + sr.consume(innerBuf.size()); + } + return ret; +} + +std::string + readBody(boost::beast::http::serializer& sr) +{ + std::string ret; + while (!sr.is_done()) + { + boost::system::error_code ec; + sr.next(ec, [&sr, &ret](const boost::system::error_code& ec2, + const auto& buffer) { + ASSERT_FALSE(ec2); + ret += collectFromBuffers(buffer, sr); + }); + EXPECT_FALSE(ec); + } + + return ret; +} +std::string getData(crow::Response::file_response& m) +{ + boost::beast::http::serializer sr{m}; + std::stringstream ret; + sr.split(true); + readHeader(sr); + return readBody(sr); +} TEST(HttpResponse, Defaults) { crow::Response res; @@ -60,17 +119,41 @@ TEST(HttpResponse, FileBody) { crow::Response res; addHeaders(res); - std::string path = makeFile(); + std::string path = makeFile("sample text"); res.openFile(path); verifyHeaders(res); std::filesystem::remove(path); } +TEST(HttpResponse, FileBodyWithFd) +{ + crow::Response res; + addHeaders(res); + std::string path = makeFile("sample text"); + FILE* fd = fopen(path.c_str(), "r+"); + res.openFd(fileno(fd)); + verifyHeaders(res); + fclose(fd); + std::filesystem::remove(path); +} + +TEST(HttpResponse, Base64FileBodyWithFd) +{ + crow::Response res; + addHeaders(res); + std::string path = makeFile("sample text"); + FILE* fd = fopen(path.c_str(), "r+"); + res.openFd(fileno(fd), bmcweb::EncodingType::Base64); + verifyHeaders(res); + fclose(fd); + std::filesystem::remove(path); +} + TEST(HttpResponse, BodyTransitions) { crow::Response res; addHeaders(res); - std::string path = makeFile(); + std::string path = makeFile("sample text"); res.openFile(path); EXPECT_EQ(boost::variant2::holds_alternative( @@ -88,4 +171,67 @@ TEST(HttpResponse, BodyTransitions) verifyHeaders(res); std::filesystem::remove(path); } + +void testFileData(crow::Response& res, const std::string& data) +{ + auto& fb = + boost::variant2::get(res.response); + EXPECT_EQ(getData(fb), data); +} + +TEST(HttpResponse, Base64FileBodyWriter) +{ + crow::Response res; + std::string data = "sample text"; + std::string path = makeFile(data); + FILE* f = fopen(path.c_str(), "r+"); + res.openFd(fileno(f), bmcweb::EncodingType::Base64); + testFileData(res, crow::utility::base64encode(data)); + fclose(f); + std::filesystem::remove(path); +} + +std::string generateBigdata() +{ + std::string result; + while (result.size() < 10000) + { + result += "sample text"; + } + return result; +} + +TEST(HttpResponse, Base64FileBodyWriterLarge) +{ + crow::Response res; + std::string data = generateBigdata(); + std::string path = makeFile(data); + { + boost::beast::file_posix file; + boost::system::error_code ec; + file.open(path.c_str(), boost::beast::file_mode::read, ec); + EXPECT_EQ(ec.value(), 0); + res.openFd(file.native_handle(), bmcweb::EncodingType::Base64); + testFileData(res, crow::utility::base64encode(data)); + } + + std::filesystem::remove(path); +} + +TEST(HttpResponse, FileBodyWriterLarge) +{ + crow::Response res; + std::string data = generateBigdata(); + std::string path = makeFile(data); + { + boost::beast::file_posix file; + boost::system::error_code ec; + file.open(path.c_str(), boost::beast::file_mode::read, ec); + EXPECT_EQ(ec.value(), 0); + res.openFd(file.native_handle()); + testFileData(res, data); + } + std::filesystem::remove(path); +} + } // namespace -- cgit v1.2.3