blob: d43d3c585e2c19b6cc1c9729c37c0f253f7ee1a8 [file]
/** @file
Catch based unit tests for HTTP overridable configuration APIs.
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "iocore/eventsystem/ConfigProcessor.h"
#include "iocore/net/ConnectionTracker.h"
#include "proxy/http/HttpConfig.h"
#include "proxy/http/HttpSM.h"
#include "proxy/http/OverridableConfigDefs.h"
#include "ts/ts.h"
#include <catch2/catch_test_macros.hpp>
#include <array>
#include <string>
#include <string_view>
namespace
{
struct ConfigDescriptor {
std::string_view name;
TSOverridableConfigKey key;
TSRecordDataType type;
};
// clang-format off
static constexpr std::array<ConfigDescriptor, TS_CONFIG_LAST_ENTRY> CONFIG_DESCRIPTORS{{
#define X_CONFIG_DESCRIPTOR(CONFIG_KEY, MEMBER, RECORD_NAME, DATA_TYPE, CONV) \
{RECORD_NAME, TS_CONFIG_##CONFIG_KEY, TS_RECORDDATATYPE_##DATA_TYPE},
OVERRIDABLE_CONFIGS(X_CONFIG_DESCRIPTOR)
#undef X_CONFIG_DESCRIPTOR
}};
// clang-format on
class TestHttpTxn
{
public:
TestHttpTxn()
{
if (HttpConfig::m_id == 0) {
HttpConfig::m_id = configProcessor.set(HttpConfig::m_id, new HttpConfigParams);
}
_sm.magic = HttpSmMagic_t::ALIVE;
_sm.t_state.http_config_param = HttpConfig::acquire();
REQUIRE(_sm.t_state.http_config_param != nullptr);
_sm.t_state.txn_conf = &_sm.t_state.http_config_param->oride;
}
operator TSHttpTxn() { return reinterpret_cast<TSHttpTxn>(&_sm); }
const HttpForwarded::OptionBitSet &
forwarded_options() const
{
return _sm.t_state.txn_conf->insert_forwarded;
}
private:
HttpSM _sm;
};
} // namespace
TEST_CASE("Find HTTP overridable configurations", "[api][overridable-config]")
{
for (auto const &descriptor : CONFIG_DESCRIPTORS) {
TSOverridableConfigKey key;
TSRecordDataType type;
INFO(descriptor.name);
REQUIRE(TSHttpTxnConfigFind(descriptor.name.data(), -1, &key, &type) == TS_SUCCESS);
CHECK(key == descriptor.key);
CHECK(type == descriptor.type);
REQUIRE(TSHttpTxnConfigFind(descriptor.name.data(), static_cast<int>(descriptor.name.size()), &key, &type) == TS_SUCCESS);
CHECK(key == descriptor.key);
CHECK(type == descriptor.type);
}
TSOverridableConfigKey key;
TSRecordDataType type;
CHECK(TSHttpTxnConfigFind("proxy.config.invalid", -1, &key, &type) == TS_ERROR);
}
TEST_CASE("Round trip HTTP overridable configurations", "[api][overridable-config]")
{
TestHttpTxn txn;
for (auto const &descriptor : CONFIG_DESCRIPTORS) {
INFO(descriptor.name);
switch (descriptor.type) {
case TS_RECORDDATATYPE_INT: {
TSMgmtInt expected;
TSMgmtInt actual;
REQUIRE(TSHttpTxnConfigIntGet(txn, descriptor.key, &expected) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigIntSet(txn, descriptor.key, expected) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigIntGet(txn, descriptor.key, &actual) == TS_SUCCESS);
CHECK(actual == expected);
break;
}
case TS_RECORDDATATYPE_FLOAT: {
TSMgmtFloat expected;
TSMgmtFloat actual;
REQUIRE(TSHttpTxnConfigFloatGet(txn, descriptor.key, &expected) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigFloatSet(txn, descriptor.key, expected) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigFloatGet(txn, descriptor.key, &actual) == TS_SUCCESS);
CHECK(actual == expected);
break;
}
case TS_RECORDDATATYPE_STRING: {
if (descriptor.key == TS_CONFIG_SSL_CERT_FILEPATH) {
REQUIRE(TSHttpTxnConfigStringSet(txn, descriptor.key, "", 0) == TS_SUCCESS);
break;
}
if (descriptor.key == TS_CONFIG_HTTP_INSERT_FORWARDED) {
static constexpr std::string_view expected{"none"};
REQUIRE(TSHttpTxnConfigStringSet(txn, descriptor.key, expected.data(), static_cast<int>(expected.size())) == TS_SUCCESS);
CHECK(txn.forwarded_options().none());
break;
}
const char *value;
int length;
REQUIRE(TSHttpTxnConfigStringGet(txn, descriptor.key, &value, &length) == TS_SUCCESS);
REQUIRE(length >= 0);
REQUIRE((value != nullptr || length == 0));
std::string expected;
if (value != nullptr) {
expected.assign(value, length);
}
REQUIRE(TSHttpTxnConfigStringSet(txn, descriptor.key, expected.data(), static_cast<int>(expected.size())) == TS_SUCCESS);
const char *actual;
int actual_length;
REQUIRE(TSHttpTxnConfigStringGet(txn, descriptor.key, &actual, &actual_length) == TS_SUCCESS);
REQUIRE(actual_length >= 0);
REQUIRE((actual != nullptr || actual_length == 0));
CHECK(std::string_view(actual != nullptr ? actual : "", actual_length) == expected);
break;
}
default:
FAIL("Unexpected overridable configuration data type");
break;
}
}
}
TEST_CASE("Clamp constrained HTTP overridable configuration", "[api][overridable-config]")
{
TestHttpTxn txn;
TSMgmtInt actual;
REQUIRE(TSHttpTxnConfigIntSet(txn, TS_CONFIG_HTTP_PER_SERVER_CONNECTION_MATCH, 95) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigIntGet(txn, TS_CONFIG_HTTP_PER_SERVER_CONNECTION_MATCH, &actual) == TS_SUCCESS);
CHECK(actual == TS_SERVER_OUTBOUND_MATCH_BOTH);
}
TEST_CASE("Round trip bounded SSL string overrides", "[api][overridable-config]")
{
static constexpr std::array SSL_STRING_CONFIGS{
TS_CONFIG_SSL_CLIENT_VERIFY_SERVER_POLICY, TS_CONFIG_SSL_CLIENT_VERIFY_SERVER_PROPERTIES, TS_CONFIG_SSL_CLIENT_SNI_POLICY,
TS_CONFIG_SSL_CLIENT_CERT_FILENAME, TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME, TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME,
TS_CONFIG_SSL_CLIENT_CA_CERT_PATH, TS_CONFIG_SSL_CLIENT_ALPN_PROTOCOLS,
};
static constexpr std::array<char, 3> EXPECTED{'a', '\0', 'b'};
TestHttpTxn txn;
for (auto const key : SSL_STRING_CONFIGS) {
const char *actual;
int actual_length;
REQUIRE(TSHttpTxnConfigStringSet(txn, key, EXPECTED.data(), EXPECTED.size()) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigStringGet(txn, key, &actual, &actual_length) == TS_SUCCESS);
REQUIRE(actual != nullptr);
CHECK(actual_length == EXPECTED.size());
CHECK(std::string_view(actual, actual_length) == std::string_view(EXPECTED.data(), EXPECTED.size()));
REQUIRE(TSHttpTxnConfigStringSet(txn, key, nullptr, 0) == TS_SUCCESS);
REQUIRE(TSHttpTxnConfigStringGet(txn, key, &actual, &actual_length) == TS_SUCCESS);
CHECK(actual == nullptr);
CHECK(actual_length == 0);
}
}