Skip to content

Commit f2e178b

Browse files
committed
[QC-1260] Consider handling better invalid JSON from ccdbApi->list
The json error was already handled in the sense that it was not crashing and it was logging a human readable error. I added a test and added a bit more output in case we don't find the objects we are looking for in the listing.
1 parent 0938451 commit f2e178b

3 files changed

Lines changed: 157 additions & 2 deletions

File tree

‎Framework/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ set(TEST_SRCS
329329
test/testTaskRunner.cxx
330330
test/testObjectsManager.cxx
331331
test/testCcdbDatabase.cxx
332+
test/testCcdbDatabaseListingErrors.cxx
332333
test/testCcdbDatabaseExtra.cxx
333334
test/testTriggers.cxx
334335
test/testPostProcessingInterface.cxx
@@ -355,6 +356,7 @@ set(TEST_ARGS
355356
""
356357
""
357358
""
359+
""
358360
"-b --run"
359361
"-b --run"
360362
""

‎Framework/src/CcdbDatabase.cxx‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,12 @@ core::ValidityInterval CcdbDatabase::getLatestObjectValidity(const std::string&
524524

525525
std::vector<uint64_t> CcdbDatabase::getTimestampsForObject(const std::string& path)
526526
{
527-
const auto& objects = getListingAsPtree(path).get_child("objects");
527+
const auto listing = getListingAsPtree(path);
528+
if (listing.count("objects") == 0) {
529+
ILOG(Warning, Support) << "Could not get a valid listing from db '" << mUrl << "' for timestamps of '" << path << "'" << ENDM;
530+
return {};
531+
}
532+
const auto& objects = listing.get_child("objects");
528533
std::vector<uint64_t> timestamps;
529534
timestamps.reserve(objects.size());
530535

@@ -551,7 +556,13 @@ std::vector<std::string> CcdbDatabase::getPublishedObjectNames(std::string taskN
551556
try {
552557
boost::property_tree::read_json(ss, pt);
553558
} catch (const boost::property_tree::json_parser::json_parser_error&) {
554-
ILOG(Error, Support) << "Failed to parse json in CcdbDatabase::getTimestampsForObject from data: " << ss.str() << ENDM;
559+
ILOG(Error, Support) << "Failed to parse json in CcdbDatabase::getPublishedObjectNames from data: " << listing << ENDM;
560+
return result;
561+
}
562+
563+
if (pt.count("objects") == 0) {
564+
ILOG(Warning, Support) << "Could not get a valid listing from db '" << mUrl << "' for published objects of '" << taskName << "'" << ENDM;
565+
return result;
555566
}
556567

557568
BOOST_FOREACH (boost::property_tree::ptree::value_type& v, pt.get_child("objects")) {
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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

Comments
 (0)