| // 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_ |