blob: 7ed14c177a4b509c8b23b7d6fe3281fd0f034151 [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 <algorithm>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <base/values.h>
#include <base/json/json_reader.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "runtime_probe/functions/sequence.h"
#include "runtime_probe/functions/shell.h"
#include "runtime_probe/probe_function.h"
namespace runtime_probe {
typedef ProbeFunction::DataType DataType;
class MockProbeFunction : public ProbeFunction {
public:
MOCK_CONST_METHOD0(Eval, DataType());
};
TEST(SequenceFunctionTest, TestEvalFailTooManyResults) {
auto mock_probe_function_1 = std::make_unique<MockProbeFunction>();
base::DictionaryValue a;
a.SetBoolean("a", true);
base::DictionaryValue b;
b.SetBoolean("b", true);
EXPECT_CALL(*mock_probe_function_1, Eval())
.WillOnce(testing::Return(DataType{a, b}));
auto mock_probe_function_2 = std::make_unique<MockProbeFunction>();
// The sequence function should abort after calling mock_probe_function_1,
// mock_probe_function_2 should never be called.
SequenceFunction sequence{};
sequence.functions_.push_back(std::move(mock_probe_function_1));
sequence.functions_.push_back(std::move(mock_probe_function_2));
DataType results = sequence.Eval();
std::stringstream stream;
for (auto result : results) {
stream << result;
}
/* The `results` should be empty */
ASSERT_EQ(results.size(), 0) << "unexpected results: " << stream.str();
return;
}
TEST(SequenceFunctionTest, TestEvalSuccess) {
auto mock_probe_function_1 = std::make_unique<MockProbeFunction>();
base::DictionaryValue a;
a.SetBoolean("a", true);
a.SetBoolean("c", false);
EXPECT_CALL(*mock_probe_function_1, Eval())
.WillOnce(testing::Return(DataType{a}));
auto mock_probe_function_2 = std::make_unique<MockProbeFunction>();
base::DictionaryValue b;
b.SetBoolean("b", true);
b.SetBoolean("c", true);
EXPECT_CALL(*mock_probe_function_2, Eval())
.WillOnce(testing::Return(DataType{b}));
SequenceFunction sequence{};
sequence.functions_.push_back(std::move(mock_probe_function_1));
sequence.functions_.push_back(std::move(mock_probe_function_2));
DataType results = sequence.Eval();
std::stringstream stream;
for (auto result : results) {
stream << result;
}
/* The `results` should be empty */
ASSERT_EQ(results.size(), 1) << "unexpected results: " << stream.str();
std::set<std::string> result_keys;
LOG(ERROR) << results[0];
for (base::DictionaryValue::Iterator it{results[0]}; !it.IsAtEnd();
it.Advance()) {
ASSERT_TRUE(it.value().is_bool()) << "unexpected result: " << results[0];
ASSERT_TRUE(it.value().GetBool()) << "unexpected result: " << results[0];
result_keys.insert(it.key());
}
ASSERT_THAT(result_keys, ::testing::UnorderedElementsAre("a", "b", "c"));
}
TEST(SequenceFunctionTest, TestParserEmptyList) {
auto json_object = base::JSONReader::Read(R"({
"sequence": {
"functions": []
}
})");
auto p = ProbeFunction::FromValue(*json_object);
ASSERT_NE(p, nullptr) << "Failed to load function: " << json_object;
auto sequence = dynamic_cast<SequenceFunction*>(p.get());
ASSERT_NE(sequence, nullptr) << "Loaded function is not SequenceFunction";
ASSERT_EQ(sequence->functions_.size(), 0);
}
TEST(SequenceFunctionTest, TestParseFunctions) {
auto json_object = base::JSONReader::Read(R"({
"sequence": {
"functions": [
{
"sysfs": {
"dir_path": "/sys/class/cool/device/*",
"keys": ["1", "2", "3"]
}
},
{
"sysfs": {
"dir_path": "/sys/class/some/device/*",
"keys": ["4", "5", "6"]
}
}
]
}
})");
auto p = ProbeFunction::FromValue(*json_object);
ASSERT_NE(p, nullptr) << "Failed to load function: " << json_object;
auto sequence = dynamic_cast<SequenceFunction*>(p.get());
ASSERT_NE(sequence, nullptr) << "Loaded function is not SequenceFunction";
ASSERT_EQ(sequence->functions_.size(), 2);
for (const auto& func : sequence->functions_) {
ASSERT_NE(func, nullptr);
}
}
} // namespace runtime_probe