blob: 95a2e190455ab3d233e3752e22315a0bbdb2b80b [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include <vector>
#include <base/json/json_reader.h>
#include <base/values.h>
#include <brillo/map_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "runtime_probe/probe_result_checker.h"
namespace runtime_probe {
namespace {
using ::testing::_;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::UnorderedElementsAre;
class MockProbeResultChecker : public ProbeResultChecker {
public:
MOCK_METHOD(bool, Apply, (base::Value * probe_result), (const, override));
};
} // namespace
TEST(ProbeResultCheckerDictTest, TestFromValue) {
const auto json_string = R"({
"string_field": [true, "str"],
"string_field_exact_match": [true, "str", "!eq xx[yy"],
"string_field_with_validate_rule": [true, "str", "!re hello_.*"],
"int_field": [true, "int"],
"double_field": [true, "double"],
"hex_field": [false, "hex"]
})";
auto dict_value = base::JSONReader::Read(json_string);
ASSERT_TRUE(dict_value.has_value());
ASSERT_TRUE(dict_value->is_dict());
auto expect_fields = ProbeResultCheckerDict::FromValue(*dict_value);
ASSERT_TRUE(expect_fields.get());
const auto& required = expect_fields->required_fields_;
ASSERT_THAT(brillo::GetMapKeys(required),
UnorderedElementsAre("string_field", "string_field_exact_match",
"string_field_with_validate_rule",
"int_field", "double_field"));
ASSERT_TRUE(
dynamic_cast<StringFieldConverter*>(required.at("string_field").get()));
ASSERT_TRUE(dynamic_cast<StringFieldConverter*>(
required.at("string_field_exact_match").get()));
ASSERT_TRUE(dynamic_cast<StringFieldConverter*>(
required.at("string_field_exact_match").get()));
ASSERT_TRUE(dynamic_cast<StringFieldConverter*>(
required.at("string_field_with_validate_rule").get()));
ASSERT_TRUE(
dynamic_cast<IntegerFieldConverter*>(required.at("int_field").get()));
ASSERT_TRUE(
dynamic_cast<DoubleFieldConverter*>(required.at("double_field").get()));
const auto& optional = expect_fields->optional_fields_;
ASSERT_THAT(brillo::GetMapKeys(optional), UnorderedElementsAre("hex_field"));
ASSERT_TRUE(dynamic_cast<HexFieldConverter*>(optional.at("hex_field").get()));
}
TEST(ProbeResultCheckerDictTest, TestApplySuccess) {
const auto expect_string = R"({
"str": [true, "str"],
"int": [true, "int"],
"hex": [true, "hex"],
"double": [true, "double"]
})";
const auto probe_result_string = R"({
"str": "string result",
"int": "1024",
"hex": "0x7b",
"double": "1e2"
})";
auto expect = base::JSONReader::Read(expect_string);
ASSERT_TRUE(expect.has_value());
ASSERT_TRUE(expect->is_dict());
auto probe_result = base::JSONReader::Read(probe_result_string);
ASSERT_TRUE(probe_result.has_value());
ASSERT_TRUE(probe_result->is_dict());
auto checker = ProbeResultCheckerDict::FromValue(*expect);
ASSERT_TRUE(checker->Apply(&*probe_result));
auto* str_value = probe_result->FindStringKey("str");
ASSERT_NE(str_value, nullptr);
ASSERT_EQ(*str_value, "string result");
auto int_value = probe_result->FindIntKey("int");
ASSERT_TRUE(int_value.has_value());
ASSERT_EQ(*int_value, 1024);
auto* hex_value = probe_result->FindStringKey("hex");
ASSERT_NE(hex_value, nullptr);
ASSERT_EQ(*hex_value, "123");
auto double_value = probe_result->FindDoubleKey("double");
ASSERT_TRUE(double_value.has_value());
ASSERT_EQ(*double_value, 100);
}
TEST(ProbeResultCheckerDictTest, TestApplyWithLimitsSuccess) {
const auto expect_string = R"({
"str": [true, "str", "!eq string result"],
"int": [true, "int", "!gt 1000"],
"hex": [true, "hex", "!ne 0x0"],
"double": [true, "double", "!lt 1e3"]
})";
const auto probe_result_string = R"({
"str": "string result",
"int": "1024",
"hex": "0x7b",
"double": "1e2"
})";
auto expect = base::JSONReader::Read(expect_string);
ASSERT_TRUE(expect.has_value());
ASSERT_TRUE(expect->is_dict());
auto probe_result = base::JSONReader::Read(probe_result_string);
ASSERT_TRUE(probe_result.has_value());
ASSERT_TRUE(probe_result->is_dict());
auto checker = ProbeResultCheckerDict::FromValue(*expect);
ASSERT_TRUE(checker->Apply(&*probe_result));
auto* str_value = probe_result->FindStringKey("str");
ASSERT_NE(str_value, nullptr);
ASSERT_EQ(*str_value, "string result");
auto int_value = probe_result->FindIntKey("int");
ASSERT_TRUE(int_value.has_value());
ASSERT_EQ(*int_value, 1024);
auto* hex_value = probe_result->FindStringKey("hex");
ASSERT_NE(hex_value, nullptr);
ASSERT_EQ(*hex_value, "123");
auto double_value = probe_result->FindDoubleKey("double");
ASSERT_TRUE(double_value.has_value());
ASSERT_EQ(*double_value, 100);
}
TEST(ProbeResultCheckerDictTest, TestApplyWithLimitsFail) {
// For each field converter, |TestValidateRule| should already check each kind
// of operators. This function only checks if |Apply| function would return
// |false| if any of the fields is invalid.
const auto expect_string = R"({
"str": [true, "str", "!eq string result"],
"int": [true, "int", "!gt 1000"],
"hex": [true, "hex", "!ne 0x0"],
"double": [true, "double", "!lt 1e3"]
})";
const auto probe_result_string = R"({
"str": "This doesn't match!",
"int": "1024",
"hex": "0x7b",
"double": "1e2"
})";
auto expect = base::JSONReader::Read(expect_string);
ASSERT_TRUE(expect.has_value());
ASSERT_TRUE(expect->is_dict());
auto probe_result = base::JSONReader::Read(probe_result_string);
ASSERT_TRUE(probe_result.has_value());
ASSERT_TRUE(probe_result->is_dict());
auto checker = ProbeResultCheckerDict::FromValue(*expect);
ASSERT_FALSE(checker->Apply(&*probe_result));
}
TEST(ProbeResultCheckerListTest, TestFromValue) {
const auto json_string = R"([
{
"string_field": [true, "str"],
"hex_field": [false, "hex"]
},
{
"string_field": [false, "str"],
"hex_field": [true, "hex"]
}
])";
const auto list_value = base::JSONReader::Read(json_string);
ASSERT_TRUE(list_value.has_value());
ASSERT_TRUE(list_value->is_list());
const auto checker_list = ProbeResultCheckerList::FromValue(*list_value);
ASSERT_EQ(checker_list->checkers.size(), 2);
{
const auto expect_fields = dynamic_cast<ProbeResultCheckerDict*>(
checker_list->checkers.at(0).get());
ASSERT_TRUE(expect_fields);
const auto& required = expect_fields->required_fields_;
ASSERT_THAT(brillo::GetMapKeys(required),
UnorderedElementsAre("string_field"));
ASSERT_TRUE(
dynamic_cast<StringFieldConverter*>(required.at("string_field").get()));
const auto& optional = expect_fields->optional_fields_;
ASSERT_THAT(brillo::GetMapKeys(optional),
UnorderedElementsAre("hex_field"));
ASSERT_TRUE(
dynamic_cast<HexFieldConverter*>(optional.at("hex_field").get()));
}
{
const auto expect_fields = dynamic_cast<ProbeResultCheckerDict*>(
checker_list->checkers.at(1).get());
ASSERT_TRUE(expect_fields);
const auto& required = expect_fields->required_fields_;
ASSERT_THAT(brillo::GetMapKeys(required),
UnorderedElementsAre("hex_field"));
ASSERT_TRUE(
dynamic_cast<HexFieldConverter*>(required.at("hex_field").get()));
const auto& optional = expect_fields->optional_fields_;
ASSERT_THAT(brillo::GetMapKeys(optional),
UnorderedElementsAre("string_field"));
ASSERT_TRUE(
dynamic_cast<StringFieldConverter*>(optional.at("string_field").get()));
}
}
TEST(ProbeResultCheckerListTest, TestApply) {
std::vector<std::pair<std::vector<bool>, bool>> testdata = {
{{}, true},
{{true}, true},
{{false}, false},
{{true, false}, true},
{{false, true}, true},
{{false, false}, false}};
for (const auto& [inputs, output] : testdata) {
auto checker_list = std::make_unique<ProbeResultCheckerList>();
for (const auto& input : inputs) {
auto mock_checker = std::make_unique<NiceMock<MockProbeResultChecker>>();
ON_CALL(*mock_checker, Apply(_)).WillByDefault(Return(input));
checker_list->checkers.push_back(std::move(mock_checker));
}
ASSERT_EQ(output, checker_list->Apply(nullptr));
}
}
TEST(ProbeResultCheckerListTest, TestApplyShortCircuit) {
auto checker_list = std::make_unique<ProbeResultCheckerList>();
auto mock_checker = std::make_unique<StrictMock<MockProbeResultChecker>>();
EXPECT_CALL(*mock_checker, Apply(_)).WillOnce(Return(true));
checker_list->checkers.push_back(std::move(mock_checker));
// This checker should not be called.
mock_checker = std::make_unique<StrictMock<MockProbeResultChecker>>();
checker_list->checkers.push_back(std::move(mock_checker));
ASSERT_TRUE(checker_list->Apply(nullptr));
}
TEST(ProbeResultCheckerTest, TestFromValueDict) {
const auto json_string = R"({})";
const auto list_value = base::JSONReader::Read(json_string);
ASSERT_TRUE(list_value.has_value());
ASSERT_TRUE(list_value->is_dict());
const auto checker = ProbeResultChecker::FromValue(*list_value);
ASSERT_TRUE(dynamic_cast<ProbeResultCheckerDict*>(checker.get()));
}
TEST(ProbeResultCheckerTest, TestFromValueList) {
const auto json_string = R"([])";
const auto list_value = base::JSONReader::Read(json_string);
ASSERT_TRUE(list_value.has_value());
ASSERT_TRUE(list_value->is_list());
const auto checker = ProbeResultChecker::FromValue(*list_value);
ASSERT_TRUE(dynamic_cast<ProbeResultCheckerList*>(checker.get()));
}
} // namespace runtime_probe