|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | + |
| 12 | +/// |
| 13 | +/// \file testCcdbDatabaseListingErrors.cxx |
| 14 | +/// \author Barthelemy von Haller |
| 15 | +/// |
| 16 | +/// Reproduces issues with CCDB |
| 17 | + |
| 18 | +#include "QualityControl/CcdbDatabase.h" |
| 19 | + |
| 20 | +#define BOOST_TEST_MODULE CcdbDatabase listing errors test |
| 21 | +#define BOOST_TEST_MAIN |
| 22 | +#define BOOST_TEST_DYN_LINK |
| 23 | + |
| 24 | +#include <boost/test/unit_test.hpp> |
| 25 | +#include <boost/property_tree/ptree.hpp> |
| 26 | + |
| 27 | +#include <arpa/inet.h> |
| 28 | +#include <netinet/in.h> |
| 29 | +#include <sys/socket.h> |
| 30 | +#include <unistd.h> |
| 31 | + |
| 32 | +#include <atomic> |
| 33 | +#include <string> |
| 34 | +#include <thread> |
| 35 | +#include <vector> |
| 36 | + |
| 37 | +using namespace o2::quality_control::repository; |
| 38 | + |
| 39 | +namespace |
| 40 | +{ |
| 41 | + |
| 42 | +constexpr const char* kServiceUnavailableHtml = |
| 43 | + "<!doctype html><html lang=\"en\"><head><title>HTTP Status 503 – Service Unavailable</title></head>" |
| 44 | + "<body><h1>HTTP Status 503 – Service Unavailable</h1>" |
| 45 | + "<p><b>Message</b> Too many concurrent requests to /browse/ or /latest/ , cannot serve more</p>" |
| 46 | + "<h3>Apache Tomcat/9.0.97</h3></body></html>"; |
| 47 | + |
| 48 | +// Junie generated |
| 49 | +class Html503Server |
| 50 | +{ |
| 51 | + public: |
| 52 | + Html503Server() |
| 53 | + { |
| 54 | + mListenFd = ::socket(AF_INET, SOCK_STREAM, 0); |
| 55 | + |
| 56 | + int yes = 1; |
| 57 | + ::setsockopt(mListenFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); |
| 58 | + |
| 59 | + sockaddr_in addr{}; |
| 60 | + addr.sin_family = AF_INET; |
| 61 | + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 62 | + addr.sin_port = htons(0); |
| 63 | + |
| 64 | + socklen_t len = sizeof(addr); |
| 65 | + mPort = ntohs(addr.sin_port); |
| 66 | + |
| 67 | + mRunning = true; |
| 68 | + mThread = std::thread([this] { run(); }); |
| 69 | + } |
| 70 | + |
| 71 | + ~Html503Server() |
| 72 | + { |
| 73 | + mRunning = false; |
| 74 | + if (mListenFd >= 0) { |
| 75 | + ::shutdown(mListenFd, SHUT_RDWR); |
| 76 | + ::close(mListenFd); |
| 77 | + mListenFd = -1; |
| 78 | + } |
| 79 | + if (mThread.joinable()) { |
| 80 | + mThread.join(); |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + std::string url() const { return "http://127.0.0.1:" + std::to_string(mPort); } |
| 85 | + |
| 86 | + private: |
| 87 | + void run() |
| 88 | + { |
| 89 | + while (mRunning) { |
| 90 | + sockaddr_in client{}; |
| 91 | + socklen_t clientLen = sizeof(client); |
| 92 | + int clientFd = ::accept(mListenFd, reinterpret_cast<sockaddr*>(&client), &clientLen); |
| 93 | + if (clientFd < 0) { |
| 94 | + continue; |
| 95 | + } |
| 96 | + char buf[1024]; |
| 97 | + ::recv(clientFd, buf, sizeof(buf), 0); |
| 98 | + |
| 99 | + const std::string body = kServiceUnavailableHtml; |
| 100 | + std::string response = |
| 101 | + "HTTP/1.1 503 Service Unavailable\r\n" |
| 102 | + "Content-Type: text/html;charset=utf-8\r\n" |
| 103 | + "Content-Length: " + |
| 104 | + std::to_string(body.size()) + |
| 105 | + "\r\n" |
| 106 | + "Connection: close\r\n" |
| 107 | + "\r\n" + |
| 108 | + body; |
| 109 | + ::send(clientFd, response.data(), response.size(), 0); |
| 110 | + ::close(clientFd); |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + int mListenFd = -1; |
| 115 | + int mPort = 0; |
| 116 | + std::atomic<bool> mRunning{ false }; |
| 117 | + std::thread mThread; |
| 118 | +}; |
| 119 | + |
| 120 | +} // namespace |
| 121 | + |
| 122 | +BOOST_AUTO_TEST_CASE(getPublishedObjectNames_handles_html_503) |
| 123 | +{ |
| 124 | + Html503Server server; |
| 125 | + CcdbDatabase db; |
| 126 | + db.connect(server.url(), "", "", ""); |
| 127 | + |
| 128 | + std::vector<std::string> names; |
| 129 | + BOOST_CHECK_NO_THROW(names = db.getPublishedObjectNames("qc/TST/MO/SomeTask")); |
| 130 | + BOOST_TEST(names.empty()); |
| 131 | +} |
| 132 | + |
| 133 | +BOOST_AUTO_TEST_CASE(getListingAsPtree_handles_html_503) |
| 134 | +{ |
| 135 | + Html503Server server; |
| 136 | + CcdbDatabase db; |
| 137 | + db.connect(server.url(), "", "", ""); |
| 138 | + |
| 139 | + boost::property_tree::ptree listing; |
| 140 | + BOOST_CHECK_NO_THROW(listing = db.getListingAsPtree("qc/TST/MO/SomeTask")); |
| 141 | + BOOST_TEST(listing.count("objects") == 0); |
| 142 | +} |
0 commit comments