blob: 5994c747a73d45899bb6011056556feba099f484 [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.
#ifndef RUNTIME_PROBE_PROBE_RESULT_CHECKER_H_
#define RUNTIME_PROBE_PROBE_RESULT_CHECKER_H_
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <pcrecpp.h>
#include <base/values.h>
#include <gtest/gtest.h>
#include "runtime_probe/utils/type_utils.h"
namespace runtime_probe {
enum class ValidatorOperator : uint8_t {
NOP = 0,
RE, // Regular Expression match
EQ, // EQual to
NE, // Not Equal to
GT, // Greater Than
GE, // Greater than or Euqal to
LT, // Less Than
LE, // Less than or Equal to
NUM_OP,
};
// Base class of field converter.
//
// Each derived class should implement one and only one constructor
// FieldConverter(const std::string& validate_rule).
class FieldConverter {
public:
enum class ReturnCode {
OK = 0,
FIELD_NOT_FOUND = 1,
// Failed to convert the field
INCOMPATIBLE_VALUE = 2,
// The operator is not supported by this converter
UNSUPPORTED_OPERATOR = 3,
// Field value is invalid
INVALID_VALUE = 4,
};
// Try to find |field_name| in |dict_value|, and convert it to expected type.
//
// @return |ReturnCode| to indicate success or reason of failure.
virtual ReturnCode Convert(const std::string& field_name,
base::Value* dict_value) const = 0;
// Check if value of |field_name| in dict_value is valid.
//
// @return |ReturnCode| to indicate success or reason of failure.
virtual ReturnCode Validate(const std::string& field_name,
base::Value* dict_value) const = 0;
virtual std::string ToString() const = 0;
virtual ~FieldConverter() = default;
};
// Convert a field to string.
//
// Supported validators:
// - "!re <Perl-compatible regular expression>"
// - "!eq <expected string>"
// - "!ne <unexpected string>"
class StringFieldConverter : public FieldConverter {
public:
ReturnCode Convert(const std::string& field_name,
base::Value* dict_value) const override;
ReturnCode Validate(const std::string& field_name,
base::Value* dict_value) const override;
std::string ToString() const override;
static std::unique_ptr<StringFieldConverter> Build(
const base::StringPiece& validate_rule);
StringFieldConverter(ValidatorOperator op, const base::StringPiece& operand)
: operator_(op), operand_(operand) {
if (op == ValidatorOperator::RE) {
// pcrecpp::RE constructor will always succeed, but might set "error()" if
// the pattern is invalid. This will be checked in |Build()|.
regex_ = std::make_unique<pcrecpp::RE>(operand.as_string());
}
}
private:
ValidatorOperator operator_;
std::string operand_;
std::unique_ptr<pcrecpp::RE> regex_;
FRIEND_TEST(StringFieldConverterTest, TestValidateRule);
};
// Numeric Field Converters convert a field into a numeric type.
// The logic of these fields are very similar. To allow implementing common
// logic with template, helper function |StringToOperand| and type alias
// |OperandType| is defined. |OperandType| is the type of |operand_| member
// variable. And |StringToOperand| converts a string to |OperandType| value
// and return true on success.
// Convert a field to integer.
//
// However, heximal value is not allowed, please use |HexFieldConverter|
// instead.
//
// Supported validators:
// - "!eq <integer>"
// - "!ne <integer>"
// - "!gt <integer>"
// - "!ge <integer>"
// - "!lt <integer>"
// - "!le <integer>"
class IntegerFieldConverter : public FieldConverter {
public:
using FieldConverter::FieldConverter;
using OperandType = int;
ReturnCode Convert(const std::string& field_name,
base::Value* dict_value) const override;
ReturnCode Validate(const std::string& field_name,
base::Value* dict_value) const override;
std::string ToString() const override;
static std::unique_ptr<IntegerFieldConverter> Build(
const base::StringPiece& validate_rule);
IntegerFieldConverter(ValidatorOperator op, OperandType operand)
: operator_(op), operand_(operand) {}
static bool StringToOperand(const std::string& s, OperandType* output) {
return StringToInt(s, output);
}
private:
ValidatorOperator operator_;
OperandType operand_;
FRIEND_TEST(IntegerFieldConverterTest, TestValidateRule);
};
// Convert a hex string field to integer.
//
// If the original field is string, this class assumes it is base 16.
// Otherwise, if the field is already a number (int or double), the behavior wil
// be identical to |IntegerFieldConverter|.
//
// Supported validators: same as |IntegerFieldConverter|
class HexFieldConverter : public FieldConverter {
public:
using FieldConverter::FieldConverter;
using OperandType = int;
ReturnCode Convert(const std::string& field_name,
base::Value* dict_value) const override;
ReturnCode Validate(const std::string& field_name,
base::Value* dict_value) const override;
std::string ToString() const override;
static std::unique_ptr<HexFieldConverter> Build(
const base::StringPiece& validate_rule);
HexFieldConverter(ValidatorOperator op, OperandType operand)
: operator_(op), operand_(operand) {}
static bool StringToOperand(const std::string& s, OperandType* output) {
return HexStringToInt(s, output);
}
private:
ValidatorOperator operator_;
OperandType operand_;
FRIEND_TEST(HexFieldConverterTest, TestValidateRule);
};
// Convert a field to double.
//
// Supported validators: same as |IntegerFieldConverter|, except the operand
// could be double.
class DoubleFieldConverter : public FieldConverter {
public:
using FieldConverter::FieldConverter;
using OperandType = double;
ReturnCode Convert(const std::string& field_name,
base::Value* dict_value) const override;
ReturnCode Validate(const std::string& field_name,
base::Value* dict_value) const override;
std::string ToString() const override;
static std::unique_ptr<DoubleFieldConverter> Build(
const base::StringPiece& validate_rule);
DoubleFieldConverter(ValidatorOperator op, OperandType operand)
: operator_(op), operand_(operand) {}
static bool StringToOperand(const std::string& s, OperandType* output) {
return StringToDouble(s, output);
}
private:
ValidatorOperator operator_;
OperandType operand_;
FRIEND_TEST(DoubleFieldConverterTest, TestValidateRule);
};
// Holds |expect| attribute of a |ProbeStatement|.
//
// |expect| attribute should be a |Value| with following format:
// {
// <key_of_probe_result>: [<required:bool>, <expected_type:string>,
// <optional_validate_rule:string>]
// }
//
// Currently, we support the following expected types:
// - "int" (use |IntegerFieldConverter|)
// - "hex" (use |HexFieldConverter|)
// - "double" (use |DoubleFieldConverter|)
// - "str" (use |StringFieldConverter|)
//
// |ProbeResultChecker| will first try to convert each field to |expected_type|.
// Then, if |optional_validate_rule| is given, will check if converted value
// match the rule.
//
// TODO(b/121354690): Handle |optional_validate_rule|.
class ProbeResultChecker {
public:
static std::unique_ptr<ProbeResultChecker> FromValue(
const base::Value& dict_value);
// Apply |expect| rules to |probe_result|
//
// @return |true| if all required fields are converted successfully.
bool Apply(base::Value* probe_result) const;
private:
std::map<std::string, std::unique_ptr<FieldConverter>> required_fields_;
std::map<std::string, std::unique_ptr<FieldConverter>> optional_fields_;
FRIEND_TEST(ProbeResultCheckerTest, TestFromValue);
};
} // namespace runtime_probe
#endif // RUNTIME_PROBE_PROBE_RESULT_CHECKER_H_