]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/tools/advisor/test/test_rule_parser.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / tools / advisor / test / test_rule_parser.py
1 # Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 # This source code is licensed under both the GPLv2 (found in the
3 # COPYING file in the root directory) and Apache 2.0 License
4 # (found in the LICENSE.Apache file in the root directory).
5
6 import os
7 import unittest
8 from advisor.rule_parser import RulesSpec
9 from advisor.db_log_parser import DatabaseLogs, DataSource
10 from advisor.db_options_parser import DatabaseOptions
11
12 RuleToSuggestions = {
13 "stall-too-many-memtables": [
14 'inc-bg-flush',
15 'inc-write-buffer'
16 ],
17 "stall-too-many-L0": [
18 'inc-max-subcompactions',
19 'inc-max-bg-compactions',
20 'inc-write-buffer-size',
21 'dec-max-bytes-for-level-base',
22 'inc-l0-slowdown-writes-trigger'
23 ],
24 "stop-too-many-L0": [
25 'inc-max-bg-compactions',
26 'inc-write-buffer-size',
27 'inc-l0-stop-writes-trigger'
28 ],
29 "stall-too-many-compaction-bytes": [
30 'inc-max-bg-compactions',
31 'inc-write-buffer-size',
32 'inc-hard-pending-compaction-bytes-limit',
33 'inc-soft-pending-compaction-bytes-limit'
34 ],
35 "level0-level1-ratio": [
36 'l0-l1-ratio-health-check'
37 ]
38 }
39
40
41 class TestAllRulesTriggered(unittest.TestCase):
42 def setUp(self):
43 # load the Rules
44 this_path = os.path.abspath(os.path.dirname(__file__))
45 ini_path = os.path.join(this_path, 'input_files/triggered_rules.ini')
46 self.db_rules = RulesSpec(ini_path)
47 self.db_rules.load_rules_from_spec()
48 self.db_rules.perform_section_checks()
49 # load the data sources: LOG and OPTIONS
50 log_path = os.path.join(this_path, 'input_files/LOG-0')
51 options_path = os.path.join(this_path, 'input_files/OPTIONS-000005')
52 db_options_parser = DatabaseOptions(options_path)
53 self.column_families = db_options_parser.get_column_families()
54 db_logs_parser = DatabaseLogs(log_path, self.column_families)
55 self.data_sources = {
56 DataSource.Type.DB_OPTIONS: [db_options_parser],
57 DataSource.Type.LOG: [db_logs_parser]
58 }
59
60 def test_triggered_conditions(self):
61 conditions_dict = self.db_rules.get_conditions_dict()
62 rules_dict = self.db_rules.get_rules_dict()
63 # Make sure none of the conditions is triggered beforehand
64 for cond in conditions_dict.values():
65 self.assertFalse(cond.is_triggered(), repr(cond))
66 for rule in rules_dict.values():
67 self.assertFalse(
68 rule.is_triggered(conditions_dict, self.column_families),
69 repr(rule)
70 )
71
72 # # Trigger the conditions as per the data sources.
73 # trigger_conditions(, conditions_dict)
74
75 # Get the set of rules that have been triggered
76 triggered_rules = self.db_rules.get_triggered_rules(
77 self.data_sources, self.column_families
78 )
79
80 # Make sure each condition and rule is triggered
81 for cond in conditions_dict.values():
82 if cond.get_data_source() is DataSource.Type.TIME_SERIES:
83 continue
84 self.assertTrue(cond.is_triggered(), repr(cond))
85
86 for rule in rules_dict.values():
87 self.assertIn(rule, triggered_rules)
88 # Check the suggestions made by the triggered rules
89 for sugg in rule.get_suggestions():
90 self.assertIn(sugg, RuleToSuggestions[rule.name])
91
92 for rule in triggered_rules:
93 self.assertIn(rule, rules_dict.values())
94 for sugg in RuleToSuggestions[rule.name]:
95 self.assertIn(sugg, rule.get_suggestions())
96
97
98 class TestConditionsConjunctions(unittest.TestCase):
99 def setUp(self):
100 # load the Rules
101 this_path = os.path.abspath(os.path.dirname(__file__))
102 ini_path = os.path.join(this_path, 'input_files/test_rules.ini')
103 self.db_rules = RulesSpec(ini_path)
104 self.db_rules.load_rules_from_spec()
105 self.db_rules.perform_section_checks()
106 # load the data sources: LOG and OPTIONS
107 log_path = os.path.join(this_path, 'input_files/LOG-1')
108 options_path = os.path.join(this_path, 'input_files/OPTIONS-000005')
109 db_options_parser = DatabaseOptions(options_path)
110 self.column_families = db_options_parser.get_column_families()
111 db_logs_parser = DatabaseLogs(log_path, self.column_families)
112 self.data_sources = {
113 DataSource.Type.DB_OPTIONS: [db_options_parser],
114 DataSource.Type.LOG: [db_logs_parser]
115 }
116
117 def test_condition_conjunctions(self):
118 conditions_dict = self.db_rules.get_conditions_dict()
119 rules_dict = self.db_rules.get_rules_dict()
120 # Make sure none of the conditions is triggered beforehand
121 for cond in conditions_dict.values():
122 self.assertFalse(cond.is_triggered(), repr(cond))
123 for rule in rules_dict.values():
124 self.assertFalse(
125 rule.is_triggered(conditions_dict, self.column_families),
126 repr(rule)
127 )
128
129 # Trigger the conditions as per the data sources.
130 self.db_rules.trigger_conditions(self.data_sources)
131
132 # Check for the conditions
133 conds_triggered = ['log-1-true', 'log-2-true', 'log-3-true']
134 conds_not_triggered = ['log-4-false', 'options-1-false']
135 for cond in conds_triggered:
136 self.assertTrue(conditions_dict[cond].is_triggered(), repr(cond))
137 for cond in conds_not_triggered:
138 self.assertFalse(conditions_dict[cond].is_triggered(), repr(cond))
139
140 # Check for the rules
141 rules_triggered = ['multiple-conds-true']
142 rules_not_triggered = [
143 'single-condition-false',
144 'multiple-conds-one-false',
145 'multiple-conds-all-false'
146 ]
147 for rule_name in rules_triggered:
148 rule = rules_dict[rule_name]
149 self.assertTrue(
150 rule.is_triggered(conditions_dict, self.column_families),
151 repr(rule)
152 )
153 for rule_name in rules_not_triggered:
154 rule = rules_dict[rule_name]
155 self.assertFalse(
156 rule.is_triggered(conditions_dict, self.column_families),
157 repr(rule)
158 )
159
160
161 class TestSanityChecker(unittest.TestCase):
162 def setUp(self):
163 this_path = os.path.abspath(os.path.dirname(__file__))
164 ini_path = os.path.join(this_path, 'input_files/rules_err1.ini')
165 db_rules = RulesSpec(ini_path)
166 db_rules.load_rules_from_spec()
167 self.rules_dict = db_rules.get_rules_dict()
168 self.conditions_dict = db_rules.get_conditions_dict()
169 self.suggestions_dict = db_rules.get_suggestions_dict()
170
171 def test_rule_missing_suggestions(self):
172 regex = '.*rule must have at least one suggestion.*'
173 with self.assertRaisesRegex(ValueError, regex):
174 self.rules_dict['missing-suggestions'].perform_checks()
175
176 def test_rule_missing_conditions(self):
177 regex = '.*rule must have at least one condition.*'
178 with self.assertRaisesRegex(ValueError, regex):
179 self.rules_dict['missing-conditions'].perform_checks()
180
181 def test_condition_missing_regex(self):
182 regex = '.*provide regex for log condition.*'
183 with self.assertRaisesRegex(ValueError, regex):
184 self.conditions_dict['missing-regex'].perform_checks()
185
186 def test_condition_missing_options(self):
187 regex = '.*options missing in condition.*'
188 with self.assertRaisesRegex(ValueError, regex):
189 self.conditions_dict['missing-options'].perform_checks()
190
191 def test_condition_missing_expression(self):
192 regex = '.*expression missing in condition.*'
193 with self.assertRaisesRegex(ValueError, regex):
194 self.conditions_dict['missing-expression'].perform_checks()
195
196 def test_suggestion_missing_option(self):
197 regex = '.*provide option or description.*'
198 with self.assertRaisesRegex(ValueError, regex):
199 self.suggestions_dict['missing-option'].perform_checks()
200
201 def test_suggestion_missing_description(self):
202 regex = '.*provide option or description.*'
203 with self.assertRaisesRegex(ValueError, regex):
204 self.suggestions_dict['missing-description'].perform_checks()
205
206
207 class TestParsingErrors(unittest.TestCase):
208 def setUp(self):
209 self.this_path = os.path.abspath(os.path.dirname(__file__))
210
211 def test_condition_missing_source(self):
212 ini_path = os.path.join(self.this_path, 'input_files/rules_err2.ini')
213 db_rules = RulesSpec(ini_path)
214 regex = '.*provide source for condition.*'
215 with self.assertRaisesRegex(NotImplementedError, regex):
216 db_rules.load_rules_from_spec()
217
218 def test_suggestion_missing_action(self):
219 ini_path = os.path.join(self.this_path, 'input_files/rules_err3.ini')
220 db_rules = RulesSpec(ini_path)
221 regex = '.*provide action for option.*'
222 with self.assertRaisesRegex(ValueError, regex):
223 db_rules.load_rules_from_spec()
224
225 def test_section_no_name(self):
226 ini_path = os.path.join(self.this_path, 'input_files/rules_err4.ini')
227 db_rules = RulesSpec(ini_path)
228 regex = 'Parsing error: needed section header:.*'
229 with self.assertRaisesRegex(ValueError, regex):
230 db_rules.load_rules_from_spec()
231
232
233 if __name__ == '__main__':
234 unittest.main()