diff --git a/core/common/http/AsynCurlRunner.cpp b/core/common/http/AsynCurlRunner.cpp index 6b51b63eec..a5201fb609 100644 --- a/core/common/http/AsynCurlRunner.cpp +++ b/core/common/http/AsynCurlRunner.cpp @@ -88,7 +88,10 @@ bool AsynCurlRunner::AddRequestToClient(unique_ptr&& request) { headers, request->mTimeout, AppConfig::GetInstance()->IsHostIPReplacePolicyEnabled(), - AppConfig::GetInstance()->GetBindInterface()); + AppConfig::GetInstance()->GetBindInterface(), + request->mFollowRedirects, + request->mTls); + if (curl == nullptr) { LOG_ERROR(sLogger, ("failed to send request", "failed to init curl handler")("request address", request.get())); request->OnSendDone(request->mResponse); @@ -135,9 +138,7 @@ void AsynCurlRunner::DoRun() { } } - struct timeval timeout { - 1, 0 - }; + struct timeval timeout{1, 0}; long curlTimeout = -1; if ((mc = curl_multi_timeout(mClient, &curlTimeout)) != CURLM_OK) { LOG_WARNING( diff --git a/core/common/http/Curl.cpp b/core/common/http/Curl.cpp index feeae3c0f8..19778c2abc 100644 --- a/core/common/http/Curl.cpp +++ b/core/common/http/Curl.cpp @@ -69,7 +69,9 @@ CURL* CreateCurlHandler(const std::string& method, curl_slist*& headers, uint32_t timeout, bool replaceHostWithIp, - const std::string& intf) { + const std::string& intf, + bool followRedirects, + std::optional tls) { static DnsCache* dnsCache = DnsCache::GetInstance(); CURL* curl = curl_easy_init(); @@ -102,11 +104,28 @@ CURL* CreateCurlHandler(const std::string& method, curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.size()); } + if (followRedirects) { + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + } + if (httpsFlag) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } + if (tls.has_value()) { + if (!tls->mCaFile.empty()) { + curl_easy_setopt(curl, CURLOPT_CAINFO, tls->mCaFile.c_str()); + } + if (!tls->mCertFile.empty()) { + curl_easy_setopt(curl, CURLOPT_SSLCERT, tls->mCertFile.c_str()); + } + if (!tls->mKeyFile.empty()) { + curl_easy_setopt(curl, CURLOPT_SSLKEY, tls->mKeyFile.c_str()); + } + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, tls->mInsecureSkipVerify ? 0 : 1); + } + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); if (!intf.empty()) { curl_easy_setopt(curl, CURLOPT_INTERFACE, intf.c_str()); @@ -139,7 +158,9 @@ bool SendHttpRequest(std::unique_ptr&& request, HttpResponse& respo headers, request->mTimeout, AppConfig::GetInstance()->IsHostIPReplacePolicyEnabled(), - AppConfig::GetInstance()->GetBindInterface()); + AppConfig::GetInstance()->GetBindInterface(), + request->mFollowRedirects, + request->mTls); if (curl == NULL) { LOG_ERROR(sLogger, ("failed to init curl handler", "failed to init curl client")("request address", request.get())); diff --git a/core/common/http/Curl.h b/core/common/http/Curl.h index 0280d6ad1a..e1f311c017 100644 --- a/core/common/http/Curl.h +++ b/core/common/http/Curl.h @@ -20,8 +20,8 @@ #include #include -#include #include +#include #include "common/http/HttpRequest.h" #include "common/http/HttpResponse.h" @@ -40,7 +40,9 @@ CURL* CreateCurlHandler(const std::string& method, curl_slist*& headers, uint32_t timeout, bool replaceHostWithIp = true, - const std::string& intf = ""); + const std::string& intf = "", + bool followRedirects = false, + std::optional tls = std::nullopt); bool SendHttpRequest(std::unique_ptr&& request, HttpResponse& response); diff --git a/core/common/http/HttpRequest.h b/core/common/http/HttpRequest.h index af612c35ed..13ef2db70c 100644 --- a/core/common/http/HttpRequest.h +++ b/core/common/http/HttpRequest.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "common/Flags.h" #include "common/http/HttpResponse.h" @@ -29,6 +30,13 @@ DECLARE_FLAG_INT32(default_http_request_max_try_cnt); namespace logtail { +struct CurlTLS { + std::string mCaFile; + std::string mCertFile; + std::string mKeyFile; + bool mInsecureSkipVerify = true; +}; + struct HttpRequest { std::string mMethod; // TODO: upgrade curl to 7.62, and replace the following 4 members @@ -43,6 +51,8 @@ struct HttpRequest { int32_t mPort; uint32_t mTimeout = static_cast(INT32_FLAG(default_http_request_timeout_secs)); uint32_t mMaxTryCnt = static_cast(INT32_FLAG(default_http_request_max_try_cnt)); + bool mFollowRedirects = false; + std::optional mTls = std::nullopt; uint32_t mTryCnt = 1; std::chrono::system_clock::time_point mLastSendTime; @@ -56,7 +66,9 @@ struct HttpRequest { const std::map& header, const std::string& body, uint32_t timeout = static_cast(INT32_FLAG(default_http_request_timeout_secs)), - uint32_t maxTryCnt = static_cast(INT32_FLAG(default_http_request_max_try_cnt))) + uint32_t maxTryCnt = static_cast(INT32_FLAG(default_http_request_max_try_cnt)), + bool followRedirects = false, + std::optional tls = std::nullopt) : mMethod(method), mHTTPSFlag(httpsFlag), mUrl(url), @@ -66,7 +78,9 @@ struct HttpRequest { mHost(host), mPort(port), mTimeout(timeout), - mMaxTryCnt(maxTryCnt) {} + mMaxTryCnt(maxTryCnt), + mFollowRedirects(followRedirects), + mTls(std::move(tls)) {} virtual ~HttpRequest() = default; }; @@ -85,8 +99,11 @@ struct AsynHttpRequest : public HttpRequest { const std::string& body, HttpResponse&& response = HttpResponse(), uint32_t timeout = static_cast(INT32_FLAG(default_http_request_timeout_secs)), - uint32_t maxTryCnt = static_cast(INT32_FLAG(default_http_request_max_try_cnt))) - : HttpRequest(method, httpsFlag, host, port, url, query, header, body, timeout, maxTryCnt), + uint32_t maxTryCnt = static_cast(INT32_FLAG(default_http_request_max_try_cnt)), + bool followRedirects = false, + std::optional tls = std::nullopt) + : HttpRequest( + method, httpsFlag, host, port, url, query, header, body, timeout, maxTryCnt, followRedirects, std::move(tls)), mResponse(std::move(response)) {} virtual bool IsContextValid() const = 0; diff --git a/core/common/http/HttpResponse.h b/core/common/http/HttpResponse.h index 720aef01d1..70b1d228b7 100644 --- a/core/common/http/HttpResponse.h +++ b/core/common/http/HttpResponse.h @@ -26,6 +26,8 @@ class curl_slist; namespace logtail { +struct CurlTLS; + bool caseInsensitiveComp(const char lhs, const char rhs); bool compareHeader(const std::string& lhs, const std::string& rhs); @@ -45,7 +47,9 @@ class HttpResponse { curl_slist*& headers, uint32_t timeout, bool replaceHostWithIp, - const std::string& intf); + const std::string& intf, + bool followRedirects, + std::optional tls); public: HttpResponse() diff --git a/core/prometheus/Constants.h b/core/prometheus/Constants.h index 55c6712e12..3c716587e7 100644 --- a/core/prometheus/Constants.h +++ b/core/prometheus/Constants.h @@ -69,6 +69,14 @@ const char* const PASSWORD_FILE = "password_file"; const char* const BASIC_PREFIX = "Basic "; const char* const HONOR_LABELS = "honor_labels"; const char* const HONOR_TIMESTAMPS = "honor_timestamps"; +const char* const FOLLOW_REDIRECTS = "follow_redirects"; +const char* const TLS_CONFIG = "tls_config"; +const char* const CA_FILE = "ca_file"; +const char* const CERT_FILE = "cert_file"; +const char* const KEY_FILE = "key_file"; +const char* const SERVER_NAME = "server_name"; +const char* const HOST = "Host"; +const char* const INSECURE_SKIP_VERIFY = "insecure_skip_verify"; // scrape protocols, from https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config // text/plain, application/openmetrics-text will be used diff --git a/core/prometheus/async/PromHttpRequest.cpp b/core/prometheus/async/PromHttpRequest.cpp index cf7001f270..1f7b6a4eaa 100644 --- a/core/prometheus/async/PromHttpRequest.cpp +++ b/core/prometheus/async/PromHttpRequest.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "common/http/HttpRequest.h" @@ -20,7 +21,9 @@ PromHttpRequest::PromHttpRequest(const std::string& method, uint32_t timeout, uint32_t maxTryCnt, std::shared_ptr> future, - std::shared_ptr> isContextValidFuture) + std::shared_ptr> isContextValidFuture, + bool followRedirects, + std::optional tls) : AsynHttpRequest(method, httpsFlag, host, @@ -31,7 +34,9 @@ PromHttpRequest::PromHttpRequest(const std::string& method, body, std::move(response), timeout, - maxTryCnt), + maxTryCnt, + followRedirects, + std::move(tls)), mFuture(std::move(future)), mIsContextValidFuture(std::move(isContextValidFuture)) { } diff --git a/core/prometheus/async/PromHttpRequest.h b/core/prometheus/async/PromHttpRequest.h index e54203eb11..1665b275b6 100644 --- a/core/prometheus/async/PromHttpRequest.h +++ b/core/prometheus/async/PromHttpRequest.h @@ -23,7 +23,9 @@ class PromHttpRequest : public AsynHttpRequest { uint32_t timeout, uint32_t maxTryCnt, std::shared_ptr> future, - std::shared_ptr> isContextValidFuture = nullptr); + std::shared_ptr> isContextValidFuture = nullptr, + bool followRedirects = false, + std::optional tls = std::nullopt); PromHttpRequest(const PromHttpRequest&) = default; ~PromHttpRequest() override = default; diff --git a/core/prometheus/schedulers/ScrapeConfig.cpp b/core/prometheus/schedulers/ScrapeConfig.cpp index 027c534226..3946bf54a2 100644 --- a/core/prometheus/schedulers/ScrapeConfig.cpp +++ b/core/prometheus/schedulers/ScrapeConfig.cpp @@ -22,10 +22,13 @@ ScrapeConfig::ScrapeConfig() mHonorLabels(false), mHonorTimestamps(true), mScheme("http"), + mFollowRedirects(true), + mEnableTLS(false), mMaxScrapeSizeBytes(0), mSampleLimit(0), mSeriesLimit(0) { } + bool ScrapeConfig::Init(const Json::Value& scrapeConfig) { if (!InitStaticConfig(scrapeConfig)) { return false; @@ -41,6 +44,17 @@ bool ScrapeConfig::Init(const Json::Value& scrapeConfig) { InitScrapeProtocols(nullJson); } + if (scrapeConfig.isMember(prometheus::FOLLOW_REDIRECTS) && scrapeConfig[prometheus::FOLLOW_REDIRECTS].isBool()) { + mFollowRedirects = scrapeConfig[prometheus::FOLLOW_REDIRECTS].asBool(); + } + + if (scrapeConfig.isMember(prometheus::TLS_CONFIG) && scrapeConfig[prometheus::TLS_CONFIG].isObject()) { + if (!InitTLSConfig(scrapeConfig[prometheus::TLS_CONFIG])) { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + if (scrapeConfig.isMember(prometheus::ENABLE_COMPRESSION) && scrapeConfig[prometheus::ENABLE_COMPRESSION].isBool()) { // InitEnableCompression(scrapeConfig[prometheus::ENABLE_COMPRESSION].asBool()); @@ -338,4 +352,49 @@ void ScrapeConfig::InitEnableCompression(bool enableCompression) { } } +bool ScrapeConfig::InitTLSConfig(const Json::Value& tlsConfig) { + if (tlsConfig.isMember(prometheus::CA_FILE)) { + if (tlsConfig[prometheus::CA_FILE].isString()) { + mTLS.mCaFile = tlsConfig[prometheus::CA_FILE].asString(); + } else { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + if (tlsConfig.isMember(prometheus::CERT_FILE)) { + if (tlsConfig[prometheus::CERT_FILE].isString()) { + mTLS.mCertFile = tlsConfig[prometheus::CERT_FILE].asString(); + } else { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + if (tlsConfig.isMember(prometheus::KEY_FILE)) { + if (tlsConfig[prometheus::KEY_FILE].isString()) { + mTLS.mKeyFile = tlsConfig[prometheus::KEY_FILE].asString(); + } else { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + if (tlsConfig.isMember(prometheus::SERVER_NAME)) { + if (tlsConfig[prometheus::SERVER_NAME].isString()) { + mRequestHeaders[prometheus::HOST] = tlsConfig[prometheus::SERVER_NAME].asString(); + } else { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + if (tlsConfig.isMember(prometheus::INSECURE_SKIP_VERIFY)) { + if (tlsConfig[prometheus::INSECURE_SKIP_VERIFY].isBool()) { + mTLS.mInsecureSkipVerify = tlsConfig[prometheus::INSECURE_SKIP_VERIFY].asBool(); + } else { + LOG_ERROR(sLogger, ("tls config error", "")); + return false; + } + } + mEnableTLS = true; + return true; +} + } // namespace logtail \ No newline at end of file diff --git a/core/prometheus/schedulers/ScrapeConfig.h b/core/prometheus/schedulers/ScrapeConfig.h index 4af52c39f0..38e5087ccc 100644 --- a/core/prometheus/schedulers/ScrapeConfig.h +++ b/core/prometheus/schedulers/ScrapeConfig.h @@ -7,6 +7,7 @@ #include #include +#include "common/http/HttpRequest.h" #include "prometheus/labels/Relabel.h" @@ -28,6 +29,10 @@ class ScrapeConfig { // enable_compression Accept-Encoding header: gzip, identity std::map mRequestHeaders; + bool mFollowRedirects; + bool mEnableTLS; + CurlTLS mTLS; + uint64_t mMaxScrapeSizeBytes; uint64_t mSampleLimit; uint64_t mSeriesLimit; @@ -47,6 +52,7 @@ class ScrapeConfig { bool InitAuthorization(const Json::Value& authorization); bool InitScrapeProtocols(const Json::Value& scrapeProtocols); void InitEnableCompression(bool enableCompression); + bool InitTLSConfig(const Json::Value& tlsConfig); #ifdef APSARA_UNIT_TEST_MAIN friend class ScrapeConfigUnittest; diff --git a/core/prometheus/schedulers/ScrapeScheduler.cpp b/core/prometheus/schedulers/ScrapeScheduler.cpp index 02fca2caec..81d59fcf28 100644 --- a/core/prometheus/schedulers/ScrapeScheduler.cpp +++ b/core/prometheus/schedulers/ScrapeScheduler.cpp @@ -200,23 +200,25 @@ std::unique_ptr ScrapeScheduler::BuildScrapeTimerEvent(std::chrono:: if (retry > 0) { retry -= 1; } - auto request - = std::make_unique(sdk::HTTP_GET, - mScrapeConfigPtr->mScheme == prometheus::HTTPS, - mHost, - mPort, - mScrapeConfigPtr->mMetricsPath, - mScrapeConfigPtr->mQueryString, - mScrapeConfigPtr->mRequestHeaders, - "", - HttpResponse( - new PromMetricResponseBody(mEventPool), - [](void* ptr) { delete static_cast(ptr); }, - PromMetricWriteCallback), - mScrapeConfigPtr->mScrapeTimeoutSeconds, - retry, - this->mFuture, - this->mIsContextValidFuture); + auto request = std::make_unique( + sdk::HTTP_GET, + mScrapeConfigPtr->mScheme == prometheus::HTTPS, + mHost, + mPort, + mScrapeConfigPtr->mMetricsPath, + mScrapeConfigPtr->mQueryString, + mScrapeConfigPtr->mRequestHeaders, + "", + HttpResponse( + new PromMetricResponseBody(mEventPool), + [](void* ptr) { delete static_cast(ptr); }, + PromMetricWriteCallback), + mScrapeConfigPtr->mScrapeTimeoutSeconds, + retry, + this->mFuture, + this->mIsContextValidFuture, + mScrapeConfigPtr->mFollowRedirects, + mScrapeConfigPtr->mEnableTLS ? std::optional(mScrapeConfigPtr->mTLS) : std::nullopt); auto timerEvent = std::make_unique(execTime, std::move(request)); return timerEvent; } @@ -247,7 +249,8 @@ void ScrapeScheduler::InitSelfMonitor(const MetricLabels& defaultLabels) { mSelfMonitor->InitMetricManager(sScrapeMetricKeys, labels); - WriteMetrics::GetInstance()->PrepareMetricsRecordRef(mMetricsRecordRef, MetricCategory::METRIC_CATEGORY_PLUGIN_SOURCE, std::move(labels)); + WriteMetrics::GetInstance()->PrepareMetricsRecordRef( + mMetricsRecordRef, MetricCategory::METRIC_CATEGORY_PLUGIN_SOURCE, std::move(labels)); mPromDelayTotal = mMetricsRecordRef.CreateCounter(METRIC_PLUGIN_PROM_SCRAPE_DELAY_TOTAL); mPluginTotalDelayMs = mMetricsRecordRef.CreateCounter(METRIC_PLUGIN_TOTAL_DELAY_MS); } diff --git a/core/unittest/common/http/CurlUnittest.cpp b/core/unittest/common/http/CurlUnittest.cpp index 78780f6878..b06bffe1c9 100644 --- a/core/unittest/common/http/CurlUnittest.cpp +++ b/core/unittest/common/http/CurlUnittest.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "common/http/Curl.h" #include "common/http/HttpRequest.h" #include "common/http/HttpResponse.h" -#include "common/http/Curl.h" #include "unittest/Unittest.h" @@ -25,19 +25,57 @@ namespace logtail { class CurlUnittest : public ::testing::Test { public: void TestSendHttpRequest(); + void TestCurlTLS(); + void TestFollowRedirect(); }; void CurlUnittest::TestSendHttpRequest() { std::unique_ptr request; HttpResponse res; - request = std::make_unique("GET", false, "example.com", 80, "/path", "", map(), "", 10, 3); + request + = std::make_unique("GET", false, "example.com", 80, "/path", "", map(), "", 10, 3); + bool success = SendHttpRequest(std::move(request), res); + APSARA_TEST_TRUE(success); + APSARA_TEST_EQUAL(404, res.GetStatusCode()); +} + +void CurlUnittest::TestCurlTLS() { + // this test should not crash + std::unique_ptr request; + HttpResponse res; + CurlTLS tls; + tls.mInsecureSkipVerify = false; + tls.mCaFile = "ca.crt"; + tls.mCertFile = "client.crt"; + tls.mKeyFile = "client.key"; + + request = std::make_unique( + "GET", true, "example.com", 443, "/path", "", map(), "", 10, 3, false, tls); + bool success = SendHttpRequest(std::move(request), res); + APSARA_TEST_FALSE(success); + APSARA_TEST_EQUAL(0, res.GetStatusCode()); +} + +void CurlUnittest::TestFollowRedirect() { + std::unique_ptr request; + HttpResponse res; + CurlTLS tls; + tls.mInsecureSkipVerify = false; + tls.mCaFile = "ca.crt"; + tls.mCertFile = "client.crt"; + tls.mKeyFile = "client.key"; + + request = std::make_unique( + "GET", false, "example.com", 80, "/path", "", map(), "", 10, 3, true); bool success = SendHttpRequest(std::move(request), res); APSARA_TEST_TRUE(success); APSARA_TEST_EQUAL(404, res.GetStatusCode()); } UNIT_TEST_CASE(CurlUnittest, TestSendHttpRequest) +UNIT_TEST_CASE(CurlUnittest, TestCurlTLS) +UNIT_TEST_CASE(CurlUnittest, TestFollowRedirect) } // namespace logtail diff --git a/core/unittest/prometheus/ScrapeConfigUnittest.cpp b/core/unittest/prometheus/ScrapeConfigUnittest.cpp index 1268f1c913..cceb39089f 100644 --- a/core/unittest/prometheus/ScrapeConfigUnittest.cpp +++ b/core/unittest/prometheus/ScrapeConfigUnittest.cpp @@ -19,6 +19,7 @@ class ScrapeConfigUnittest : public testing::Test { void TestAuthorization(); void TestScrapeProtocols(); void TestEnableCompression(); + void TestTLS(); private: void SetUp() override; @@ -62,6 +63,13 @@ void ScrapeConfigUnittest::TestInit() { "PrometheusProto", "OpenMetricsText0.0.1" ], + "follow_redirects": false, + "tls_config": { + "ca_file": "ca_file", + "cert_file": "cert_file", + "key_file": "key_file", + "insecure_skip_verify": true + }, "enable_compression": false, "scheme": "http", "honor_labels": true, @@ -110,6 +118,16 @@ void ScrapeConfigUnittest::TestInit() { "vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.3," "application/openmetrics-text;version=0.0.1;q=0.2,*/*;q=0.1"); + // follow redirects + APSARA_TEST_EQUAL(scrapeConfig.mFollowRedirects, false); + + // tls + APSARA_TEST_EQUAL(scrapeConfig.mEnableTLS, true); + APSARA_TEST_EQUAL(scrapeConfig.mTLS.mCaFile, "ca_file"); + APSARA_TEST_EQUAL(scrapeConfig.mTLS.mCertFile, "cert_file"); + APSARA_TEST_EQUAL(scrapeConfig.mTLS.mKeyFile, "key_file"); + APSARA_TEST_EQUAL(scrapeConfig.mTLS.mInsecureSkipVerify, true); + // disable compression // APSARA_TEST_EQUAL(scrapeConfig.mRequestHeaders["Accept-Encoding"], "identity"); @@ -305,9 +323,7 @@ void ScrapeConfigUnittest::TestScrapeProtocols() { APSARA_TEST_TRUE(ParseJsonTable(configStr, config, errorMsg)); scrapeConfig.mRequestHeaders.clear(); APSARA_TEST_TRUE(scrapeConfig.Init(config)); - APSARA_TEST_EQUAL( - "text/plain;version=0.0.4;q=0.2,*/*;q=0.1", - scrapeConfig.mRequestHeaders["Accept"]); + APSARA_TEST_EQUAL("text/plain;version=0.0.4;q=0.2,*/*;q=0.1", scrapeConfig.mRequestHeaders["Accept"]); // Capital error configStr = R"JSON({ @@ -414,12 +430,52 @@ void ScrapeConfigUnittest::TestEnableCompression() { // APSARA_TEST_EQUAL("gzip", scrapeConfig.mRequestHeaders["Accept-Encoding"]); } +void ScrapeConfigUnittest::TestTLS() { + Json::Value config; + ScrapeConfig scrapeConfig; + string errorMsg; + string configStr; + + // default + configStr = R"JSON({ + "job_name": "test_job", + "scrape_interval": "30s", + "scrape_timeout": "30s", + "metrics_path": "/metrics", + "scheme": "http" + })JSON"; + APSARA_TEST_TRUE(ParseJsonTable(configStr, config, errorMsg)); + APSARA_TEST_TRUE(scrapeConfig.Init(config)); + APSARA_TEST_EQUAL(false, scrapeConfig.mEnableTLS); + + // enable + configStr = R"JSON({ + "job_name": "test_job", + "scrape_interval": "30s", + "scrape_timeout": "30s", + "metrics_path": "/metrics", + "scheme": "http", + "tls_config": { + "ca_file": "ca_file", + "insecure_skip_verify": false + } + })JSON"; + APSARA_TEST_TRUE(ParseJsonTable(configStr, config, errorMsg)); + APSARA_TEST_TRUE(scrapeConfig.Init(config)); + APSARA_TEST_EQUAL(true, scrapeConfig.mEnableTLS); + APSARA_TEST_EQUAL("ca_file", scrapeConfig.mTLS.mCaFile); + APSARA_TEST_EQUAL("", scrapeConfig.mTLS.mCertFile); + APSARA_TEST_EQUAL("", scrapeConfig.mTLS.mKeyFile); + APSARA_TEST_EQUAL(false, scrapeConfig.mTLS.mInsecureSkipVerify); +} + UNIT_TEST_CASE(ScrapeConfigUnittest, TestInit); UNIT_TEST_CASE(ScrapeConfigUnittest, TestAuth); UNIT_TEST_CASE(ScrapeConfigUnittest, TestBasicAuth); UNIT_TEST_CASE(ScrapeConfigUnittest, TestAuthorization); UNIT_TEST_CASE(ScrapeConfigUnittest, TestScrapeProtocols); UNIT_TEST_CASE(ScrapeConfigUnittest, TestEnableCompression); +UNIT_TEST_CASE(ScrapeConfigUnittest, TestTLS); } // namespace logtail