Skip to content

Commit 9afa40a

Browse files
Add unit-tests for PerfdataWriterConnection
There's a set of two tests for each perfdatawriter, just to make sure they can connect and send data that looks reasonably correct, and to make sure pausing actually works while the connection is stuck. Then there's a more in-depth suite of tests for PerfdataWriterConnection itself, to verify that connection handling works well in all types of scenarios. Co-authored-by: Yonas Habteab <yonas.habteab@icinga.com>
1 parent a3a94b1 commit 9afa40a

11 files changed

Lines changed: 955 additions & 0 deletions

test/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,18 @@ if(ICINGA2_WITH_NOTIFICATION)
140140
)
141141
endif()
142142

143+
if(ICINGA2_WITH_PERFDATA)
144+
list(APPEND base_test_SOURCES
145+
perfdata-elasticsearchwriter.cpp
146+
perfdata-gelfwriter.cpp
147+
perfdata-graphitewriter.cpp
148+
perfdata-influxdbwriter.cpp
149+
perfdata-opentsdbwriter.cpp
150+
perfdata-perfdatawriterconnection.cpp
151+
$<TARGET_OBJECTS:perfdata>
152+
)
153+
endif()
154+
143155
if(ICINGA2_UNITY_BUILD)
144156
mkunity_target(base test base_test_SOURCES)
145157
endif()
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#include <BoostTestTargetConfig.h>
5+
#include "perfdata/elasticsearchwriter.hpp"
6+
#include "test/base-testloggerfixture.hpp"
7+
#include "test/perfdata-perfdatawriterfixture.hpp"
8+
#include "test/utils.hpp"
9+
10+
using namespace icinga;
11+
12+
BOOST_FIXTURE_TEST_SUITE(perfdata_elasticsearchwriter, PerfdataWriterFixture<ElasticsearchWriter>,
13+
*boost::unit_test::label("perfdata")
14+
*boost::unit_test::label("network")
15+
)
16+
17+
BOOST_AUTO_TEST_CASE(connect)
18+
{
19+
ResumeWriter();
20+
21+
ReceiveCheckResults(1, ServiceState::ServiceCritical);
22+
23+
Accept();
24+
auto resp = GetSplitDecodedRequestBody();
25+
SendResponse();
26+
27+
// ElasticsearchWriter wants to send the same message twice, once for the check result
28+
// and once for the "state change".
29+
resp = GetSplitDecodedRequestBody();
30+
SendResponse();
31+
32+
// Just some basic sanity tests. It's not important to check if everything is entirely
33+
// correct here.
34+
BOOST_REQUIRE_GT(resp->GetLength(), 1);
35+
Dictionary::Ptr cr = resp->Get(1);
36+
BOOST_CHECK(cr->Contains("@timestamp"));
37+
BOOST_CHECK_EQUAL(cr->Get("check_command"), "dummy");
38+
BOOST_CHECK_EQUAL(cr->Get("host"), "h1");
39+
40+
PauseWriter();
41+
}
42+
43+
BOOST_AUTO_TEST_CASE(pause_with_pending_work)
44+
{
45+
ResumeWriter();
46+
47+
// Process check-results until the writer is stuck.
48+
BOOST_REQUIRE_MESSAGE(GetWriterStuck(10s), "Failed to get Writer stuck.");
49+
50+
// Now try to pause.
51+
PauseWriter();
52+
53+
REQUIRE_LOG_MESSAGE("Connection stopped\\.", 10s);
54+
REQUIRE_LOG_MESSAGE("'ElasticsearchWriter' paused\\.", 10s);
55+
}
56+
57+
BOOST_AUTO_TEST_SUITE_END()

test/perfdata-gelfwriter.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#include <BoostTestTargetConfig.h>
5+
#include "perfdata/gelfwriter.hpp"
6+
#include "test/base-testloggerfixture.hpp"
7+
#include "test/perfdata-perfdatawriterfixture.hpp"
8+
#include "test/utils.hpp"
9+
10+
using namespace icinga;
11+
12+
BOOST_FIXTURE_TEST_SUITE(perfdata_gelfwriter, PerfdataWriterFixture<GelfWriter>,
13+
*boost::unit_test::label("perfdata")
14+
*boost::unit_test::label("network")
15+
)
16+
17+
BOOST_AUTO_TEST_CASE(connect)
18+
{
19+
ResumeWriter();
20+
21+
ReceiveCheckResults(1, ServiceState::ServiceCritical);
22+
23+
Accept();
24+
Dictionary::Ptr resp = JsonDecode(GetDataUntil('\0'));
25+
26+
// Just some basic sanity tests. It's not important to check if everything is entirely
27+
// correct here.
28+
BOOST_CHECK_CLOSE(resp->Get("timestamp").Get<double>(), Utility::GetTime(), 0.5);
29+
BOOST_CHECK_EQUAL(resp->Get("_check_command"), "dummy");
30+
BOOST_CHECK_EQUAL(resp->Get("_hostname"), "h1");
31+
PauseWriter();
32+
}
33+
34+
BOOST_AUTO_TEST_CASE(pause_with_pending_work)
35+
{
36+
ResumeWriter();
37+
38+
// Process check-results until the writer is stuck.
39+
BOOST_REQUIRE_MESSAGE(GetWriterStuck(10s), "Failed to get Writer stuck.");
40+
41+
// Now stop reading and try to pause OpenTsdbWriter.
42+
PauseWriter();
43+
44+
REQUIRE_LOG_MESSAGE("Connection stopped\\.", 1s);
45+
REQUIRE_LOG_MESSAGE("'GelfWriter' paused\\.", 1s);
46+
}
47+
48+
BOOST_AUTO_TEST_SUITE_END()

test/perfdata-graphitewriter.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#include <BoostTestTargetConfig.h>
5+
#include "base/perfdatavalue.hpp"
6+
#include "perfdata/graphitewriter.hpp"
7+
#include "test/base-testloggerfixture.hpp"
8+
#include "test/perfdata-perfdatawriterfixture.hpp"
9+
#include "test/utils.hpp"
10+
11+
using namespace icinga;
12+
13+
BOOST_FIXTURE_TEST_SUITE(perfdata_graphitewriter, PerfdataWriterFixture<GraphiteWriter>,
14+
*boost::unit_test::label("perfdata")
15+
*boost::unit_test::label("network")
16+
)
17+
18+
BOOST_AUTO_TEST_CASE(connect)
19+
{
20+
ResumeWriter();
21+
22+
ReceiveCheckResults(1, ServiceState::ServiceCritical);
23+
24+
Accept();
25+
auto msg = GetDataUntil('\n');
26+
27+
// Just some basic sanity tests. It's not important to check if everything is entirely correct here.
28+
std::string_view cmpStr{"icinga2.h1.host.dummy.perfdata.dummy.value 42"};
29+
BOOST_REQUIRE_EQUAL(msg.substr(0, cmpStr.length()), cmpStr);
30+
PauseWriter();
31+
}
32+
33+
BOOST_AUTO_TEST_CASE(pause_with_pending_work)
34+
{
35+
ResumeWriter();
36+
37+
// Process check-results until the writer is stuck.
38+
BOOST_REQUIRE_MESSAGE(GetWriterStuck(10s), "Failed to get Writer stuck.");
39+
40+
// Now stop reading and try to pause OpenTsdbWriter.
41+
PauseWriter();
42+
43+
REQUIRE_LOG_MESSAGE("Connection stopped\\.", 10s);
44+
REQUIRE_LOG_MESSAGE("'GraphiteWriter' paused\\.", 10s);
45+
}
46+
47+
BOOST_AUTO_TEST_SUITE_END()

test/perfdata-influxdbwriter.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#include <BoostTestTargetConfig.h>
5+
#include "perfdata/influxdb2writer.hpp"
6+
#include "test/base-testloggerfixture.hpp"
7+
#include "test/perfdata-perfdatawriterfixture.hpp"
8+
9+
using namespace icinga;
10+
11+
BOOST_FIXTURE_TEST_SUITE(perfdata_influxdbwriter, PerfdataWriterFixture<Influxdb2Writer>,
12+
*boost::unit_test::label("perfdata")
13+
*boost::unit_test::label("network")
14+
)
15+
16+
BOOST_AUTO_TEST_CASE(connect)
17+
{
18+
ResumeWriter();
19+
20+
ReceiveCheckResults(1, ServiceState::ServiceCritical);
21+
22+
Accept();
23+
auto req = GetSplitRequestBody(',');
24+
SendResponse(boost::beast::http::status::no_content);
25+
26+
// Just some basic sanity tests. It's not important to check if everything is entirely
27+
// correct here.
28+
BOOST_REQUIRE_EQUAL(req.size(), 3);
29+
BOOST_CHECK_EQUAL(req[0], "dummy");
30+
BOOST_CHECK_EQUAL(req[1], "hostname=h1");
31+
std::string_view perfData = "metric=dummy value=42";
32+
BOOST_CHECK_EQUAL(req[2].substr(0, perfData.length()), perfData);
33+
PauseWriter();
34+
}
35+
36+
BOOST_AUTO_TEST_CASE(pause_with_pending_work)
37+
{
38+
ResumeWriter();
39+
40+
// Process check-results until the writer is stuck.
41+
BOOST_REQUIRE_MESSAGE(GetWriterStuck(10s), "Failed to get Writer stuck.");
42+
43+
// Now try to pause.
44+
PauseWriter();
45+
46+
REQUIRE_LOG_MESSAGE("Connection stopped\\.", 10s);
47+
REQUIRE_LOG_MESSAGE("'Influxdb2Writer' paused\\.", 1s);
48+
}
49+
50+
BOOST_AUTO_TEST_SUITE_END()

test/perfdata-opentsdbwriter.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#include <BoostTestTargetConfig.h>
5+
#include "base/perfdatavalue.hpp"
6+
#include "perfdata/opentsdbwriter.hpp"
7+
#include "test/base-testloggerfixture.hpp"
8+
#include "test/perfdata-perfdatawriterfixture.hpp"
9+
#include "test/utils.hpp"
10+
11+
using namespace icinga;
12+
13+
BOOST_FIXTURE_TEST_SUITE(perfdata_opentsdbwriter, PerfdataWriterFixture<OpenTsdbWriter>,
14+
*boost::unit_test::label("perfdata")
15+
*boost::unit_test::label("network")
16+
)
17+
18+
BOOST_AUTO_TEST_CASE(connect)
19+
{
20+
ResumeWriter();
21+
22+
ReceiveCheckResults(1, ServiceState::ServiceCritical);
23+
24+
Accept();
25+
auto msg = GetDataUntil('\n');
26+
std::vector<std::string> splitMsg;
27+
boost::split(splitMsg, msg, boost::is_any_of(" "));
28+
29+
// Just some basic sanity tests. It's not important to check if everything is entirely correct here.
30+
BOOST_REQUIRE_EQUAL(splitMsg.size(), 5);
31+
BOOST_REQUIRE_EQUAL(splitMsg[0], "put");
32+
BOOST_REQUIRE_EQUAL(splitMsg[1], "icinga.host.state");
33+
BOOST_REQUIRE_CLOSE(boost::lexical_cast<double>(splitMsg[2]), Utility::GetTime(), 1);
34+
BOOST_REQUIRE_EQUAL(splitMsg[3], "1");
35+
BOOST_REQUIRE_EQUAL(splitMsg[4], "host=h1");
36+
PauseWriter();
37+
}
38+
39+
BOOST_AUTO_TEST_CASE(pause_with_pending_work)
40+
{
41+
ResumeWriter();
42+
43+
// Process check-results until the writer is stuck.
44+
BOOST_REQUIRE_MESSAGE(GetWriterStuck(10s), "Failed to get Writer stuck.");
45+
46+
// Now stop reading and try to pause OpenTsdbWriter.
47+
PauseWriter();
48+
49+
REQUIRE_LOG_MESSAGE("Connection stopped\\.", 10s);
50+
REQUIRE_LOG_MESSAGE("'OpenTsdbWriter' paused\\.", 10s);
51+
}
52+
53+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)