icinga2/test/remote-certificate-fixture.hpp
2026-04-21 16:11:57 +02:00

101 lines
3.2 KiB
C++

// SPDX-FileCopyrightText: 2025 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <BoostTestTargetConfig.h>
#include "remote/apilistener.hpp"
#include "test/base-configuration-fixture.hpp"
#include "test/test-ctest.hpp"
namespace icinga {
struct CertificateFixture : ConfigurationDataDirFixture
{
CertificateFixture()
{
namespace fs = boost::filesystem;
m_CaDir = ApiListener::GetCaDir();
m_CertsDir = ApiListener::GetCertsDir();
m_CaCrtFile = m_CertsDir / "ca.crt";
Utility::MkDirP((m_PersistentCertsDir / "ca").string(), 0700);
Utility::MkDirP((m_PersistentCertsDir / "certs").string(), 0700);
Utility::MkDirP(m_CaDir.string(), 0700);
for (const auto& entry : fs::directory_iterator{m_PersistentCertsDir / "ca"}) {
Utility::CopyFile(entry.path().string(), (m_CaDir / entry.path().filename()).string());
}
Utility::MkDirP(m_CertsDir.string(), 0700);
for (const auto& entry : fs::directory_iterator{m_PersistentCertsDir / "certs"}) {
Utility::CopyFile(entry.path().string(), (m_CertsDir / entry.path().filename()).string());
}
}
[[nodiscard]] auto GetCertFor(const std::string& name) const
{
struct Cert
{
String crtFile;
String keyFile;
String csrFile;
};
Cert cert;
cert.crtFile = (m_CertsDir / (name + ".crt")).string();
cert.keyFile = (m_CertsDir / (name + ".key")).string();
cert.csrFile = (m_CertsDir / (name + ".csr")).string();
BOOST_REQUIRE(Utility::PathExists(cert.crtFile));
BOOST_REQUIRE(Utility::PathExists(cert.keyFile));
BOOST_REQUIRE(Utility::PathExists(cert.csrFile));
return cert;
}
boost::filesystem::path m_CaDir;
boost::filesystem::path m_CertsDir;
boost::filesystem::path m_CaCrtFile;
static inline const auto m_PersistentCertsDir = boost::filesystem::current_path() / "persistent" / "certs";
};
/**
* A unit-test decorator that declares that the test requires a given set of certificates.
*
* If no list of certs is given to the constructor, the test will still require the CA to be
* generated before it executes.
*
* When adding this decorator, a CTest fixture (in the form of new setup and cleanup units) is
* generated for the CA and each certificate. These fixtures are shared by all other test-cases
* that require them and will ensure that the CA/certificates exist until all those tests complete.
*
* If the prefix argument is given to the constructor, A separate CA is generated and the
* test-cases will be ensured to not run in parallel to other tests that use a different or no
* prefix.
*/
class RequiresCertificate : public CTestPropertiesBase
{
public:
explicit RequiresCertificate(const std::vector<String>& certs, const String& prefix = "remote");
std::string Get() override;
[[nodiscard]] boost::unit_test::decorator::base_ptr clone() const override
{
return boost::unit_test::decorator::base_ptr{new RequiresCertificate{*this}};
}
void apply(boost::unit_test::test_unit&) override {}
private:
std::vector<String> m_RequiredFixtures;
static inline std::vector<String> m_CertFixtures;
static inline std::vector<String> m_CaFixtures;
static void AddCaFixture(const String& caFixtureName);
static void AddCertFixture(const String& name, const String& caFixture, const String& certFixture);
};
} // namespace icinga