blob: 219208009a93b0576c591113367fe40143490c95 [file] [log] [blame]
/**
* 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 "unit/Catch.h"
#include "ContainerInfo.h"
#include "MetricsFilter.h"
#include "utils/StringUtils.h"
namespace minifi = org::apache::nifi::minifi;
namespace {
constexpr const char* RESULT_HEADER = R"({"kind":"PodMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{},"items":[)";
constexpr const char* HELLO_WORLD_POD_HEADER = R"({"metadata":{"name":"hello-world","namespace":"default","creationTimestamp":"2022-07-15T14:08:36Z"},)"
R"("timestamp":"2022-07-15T14:08:35Z","window":"30.817s","containers":[)";
constexpr const char* HELLO_WORLD_CONTAINER_ONE = R"({"name":"echo-one","usage":{"cpu":"123n","memory":"1596Ki"}})";
constexpr const char* HELLO_WORLD_CONTAINER_TWO = R"({"name":"echo-two","usage":{"cpu":"456n","memory":"1560Ki"}})";
constexpr const char* MINIFI_POD = R"({"metadata":{"name":"minifi","namespace":"default","creationTimestamp":"2022-07-15T14:08:36Z"},)"
R"("timestamp":"2022-07-15T14:08:22Z","window":"6.342s",)"
R"("containers":[{"name":"minifi","usage":{"cpu":"924956n","memory":"8800Ki"}}]})";
constexpr const char* SYSTEM_POD = R"({"metadata":{"name":"kube-apiserver-kind-control-plane","namespace":"kube-system","creationTimestamp":"2022-07-15T14:08:36Z",)"
R"("labels":{"component":"kube-apiserver","tier":"control-plane"}},"timestamp":"2022-07-15T14:08:29Z","window":"18.516s",)"
R"("containers":[{"name":"kube-apiserver","usage":{"cpu":"83095152n","memory":"270396Ki"}}]})";
const std::string API_RESULT = minifi::utils::string::join_pack(
RESULT_HEADER, HELLO_WORLD_POD_HEADER, HELLO_WORLD_CONTAINER_ONE, ",", HELLO_WORLD_CONTAINER_TWO, "]},", MINIFI_POD, ",", SYSTEM_POD, "]}");
void testSuccessfulFiltering(const std::function<bool(const minifi::kubernetes::ContainerInfo&)>& filter, const std::string& expected_result) {
const auto filtered_result = minifi::kubernetes::metrics::filter(API_RESULT, filter);
REQUIRE(filtered_result.has_value());
CHECK(filtered_result.value() == expected_result);
}
const auto ALWAYS_TRUE = [](const minifi::kubernetes::ContainerInfo&) { return true; };
} // namespace
TEST_CASE("Without filtering, we get the full result back", "[kubernetes][metrics_filter]") {
testSuccessfulFiltering(ALWAYS_TRUE, API_RESULT);
}
TEST_CASE("We can filter to get metrics for the default namespace only", "[kubernetes][metrics_filter]") {
const auto default_namespace_only = [](const minifi::kubernetes::ContainerInfo& container_info) { return container_info.name_space == "default"; };
const auto expected_result = minifi::utils::string::join_pack(
RESULT_HEADER, HELLO_WORLD_POD_HEADER, HELLO_WORLD_CONTAINER_ONE, ",", HELLO_WORLD_CONTAINER_TWO, "]},", MINIFI_POD, "]}");
testSuccessfulFiltering(default_namespace_only, expected_result);
}
TEST_CASE("We can filter to get metrics for a selected pod only", "[kubernetes][metrics_filter]") {
const auto minifi_pod_only = [](const minifi::kubernetes::ContainerInfo& container_info) { return container_info.pod_name == "minifi"; };
const auto expected_result = minifi::utils::string::join_pack(RESULT_HEADER, MINIFI_POD, "]}");
testSuccessfulFiltering(minifi_pod_only, expected_result);
}
TEST_CASE("We can filter to get metrics for a selected container only", "[kubernetes][metrics_filter]") {
const auto one_container_only = [](const minifi::kubernetes::ContainerInfo& container_info) { return container_info.pod_name == "hello-world" && container_info.container_name == "echo-two"; };
const auto expected_result = minifi::utils::string::join_pack(RESULT_HEADER, HELLO_WORLD_POD_HEADER, HELLO_WORLD_CONTAINER_TWO, "]}]}");
testSuccessfulFiltering(one_container_only, expected_result);
}
TEST_CASE("We can filter to get no metrics (not super useful)", "[kubernetes][metrics_filter]") {
const auto always_false = [](const minifi::kubernetes::ContainerInfo&) { return false; };
const auto expected_result = minifi::utils::string::join_pack(RESULT_HEADER, "]}");
testSuccessfulFiltering(always_false, expected_result);
}
TEST_CASE("An invalid JSON will return an error", "[kubernetes][metrics_filter]") {
const auto filtered_result = minifi::kubernetes::metrics::filter(R"({"foo":1, bar:2})", ALWAYS_TRUE);
REQUIRE_FALSE(filtered_result.has_value());
CHECK(filtered_result.error() == "Error parsing the metrics received from the Kubernetes API at offset 10: Missing a name for object member.");
}
TEST_CASE("A JSON with an unexpected structure will return an error", "[kubernetes][metrics_filter]") {
const auto filtered_result = minifi::kubernetes::metrics::filter(R"({"foo":1, "bar":2})", ALWAYS_TRUE);
REQUIRE_FALSE(filtered_result.has_value());
CHECK(filtered_result.error() == "Unexpected JSON received from the Kubernetes API: missing list of 'items'");
}