2024-07-25 16:48:17 -04:00
|
|
|
"""Unit tests for buildscripts/resmokelib/testing/hooks/fuzz_runtime_parameters.py."""
|
|
|
|
|
|
|
|
|
|
import random
|
|
|
|
|
import sys
|
2024-10-10 10:59:18 -07:00
|
|
|
import unittest
|
2024-07-25 16:48:17 -04:00
|
|
|
|
|
|
|
|
import mock
|
|
|
|
|
|
|
|
|
|
from buildscripts.resmokelib.testing.hooks import fuzz_runtime_parameters as _runtime_fuzzer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestRuntimeFuzzGeneration(unittest.TestCase):
|
|
|
|
|
def assert_parameter_values_ok(self, spec, generated_values):
|
|
|
|
|
for name, val in generated_values.items():
|
|
|
|
|
options = spec[name]
|
|
|
|
|
if "isRandomizedChoice" in options:
|
|
|
|
|
lb = options["lower_bound"]
|
|
|
|
|
ub = options["upper_bound"]
|
|
|
|
|
self.assertTrue(lb <= val <= ub)
|
|
|
|
|
elif "choices" in options:
|
|
|
|
|
self.assertIn(val, options["choices"])
|
|
|
|
|
elif "min" and "max" in options:
|
|
|
|
|
self.assertTrue(options["min"] <= val <= options["max"])
|
|
|
|
|
else:
|
|
|
|
|
self.assertIn("default", options)
|
|
|
|
|
self.assertEqual(val, options["default"])
|
|
|
|
|
|
|
|
|
|
@mock.patch("buildscripts.resmokelib.testing.hooks.fuzz_runtime_parameters.time.time")
|
|
|
|
|
def test_frequency_respected(self, mock_time):
|
|
|
|
|
start_time = 1625140800
|
|
|
|
|
mock_time.return_value = start_time
|
|
|
|
|
|
2024-08-09 15:35:44 -04:00
|
|
|
test_runtime_params = {
|
|
|
|
|
"mongod": {
|
|
|
|
|
"ShardingTaskExecutorPoolMinSize": {"min": 1, "max": 50, "period": 5},
|
|
|
|
|
"ingressAdmissionControllerTicketPoolSize": {
|
|
|
|
|
"choices": [500_000, 1_000_000, 2_000_000],
|
|
|
|
|
"lower_bound": 1000,
|
|
|
|
|
"upper_bound": 5_000_000,
|
|
|
|
|
"isRandomizedChoice": True,
|
|
|
|
|
"period": 1,
|
|
|
|
|
},
|
|
|
|
|
"ingressAdmissionControlEnabled": {
|
|
|
|
|
"choices": [True, False],
|
|
|
|
|
"period": 10,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"mongos": {
|
|
|
|
|
"ShardingTaskExecutorPoolMinSize": {"min": 1, "max": 50, "period": 5},
|
|
|
|
|
},
|
|
|
|
|
}
|
2024-07-25 16:48:17 -04:00
|
|
|
|
2024-08-09 15:35:44 -04:00
|
|
|
mongod_spec = test_runtime_params["mongod"]
|
2024-07-25 16:48:17 -04:00
|
|
|
runtimeFuzzerParamState = _runtime_fuzzer.RuntimeParametersState(
|
|
|
|
|
mongod_spec, random.randrange(sys.maxsize)
|
|
|
|
|
)
|
|
|
|
|
# No time has passed; we wouldn't want to set any of these yet.
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
self.assertEqual(ret, {})
|
|
|
|
|
|
|
|
|
|
mock_time.return_value = start_time + 1
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
|
|
|
|
|
# We should set ingressAdmissionControllerTicketPoolSize now, but not ingressAdmissionControlEnabled or ShardingTaskExecutorPoolMinSize
|
|
|
|
|
param_names_to_set = ret.keys()
|
|
|
|
|
self.assertIn("ingressAdmissionControllerTicketPoolSize", param_names_to_set)
|
|
|
|
|
self.assertNotIn("ingressAdmissionControlEnabled", param_names_to_set)
|
|
|
|
|
self.assertNotIn("ShardingTaskExecutorPoolMinSize", param_names_to_set)
|
|
|
|
|
self.assert_parameter_values_ok(mongod_spec, ret)
|
|
|
|
|
|
|
|
|
|
# Don't advance time, and generate the values again. Since no time has passed, nothing should be set.
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
self.assertEqual(ret, {})
|
|
|
|
|
|
|
|
|
|
# Now advance the time enough such that ShardingTaskExecutorPoolMinSize should be set also.
|
|
|
|
|
mock_time.return_value = start_time + 5
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
param_names_to_set = ret.keys()
|
|
|
|
|
self.assertIn("ingressAdmissionControllerTicketPoolSize", param_names_to_set)
|
|
|
|
|
self.assertIn("ShardingTaskExecutorPoolMinSize", param_names_to_set)
|
|
|
|
|
self.assertNotIn("ingressAdmissionControlEnabled", param_names_to_set)
|
|
|
|
|
self.assert_parameter_values_ok(mongod_spec, ret)
|
|
|
|
|
|
|
|
|
|
# Don't advance time, and generate the values again. Since no time has passed, nothing should be set.
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
self.assertEqual(ret, {})
|
|
|
|
|
|
|
|
|
|
# Now advance the time enough such that all 3 should be set.
|
|
|
|
|
mock_time.return_value = start_time + 10
|
2024-07-29 11:14:21 -04:00
|
|
|
ret = runtimeFuzzerParamState.generate_parameters()
|
2024-07-25 16:48:17 -04:00
|
|
|
param_names_to_set = ret.keys()
|
|
|
|
|
self.assertIn("ingressAdmissionControllerTicketPoolSize", param_names_to_set)
|
|
|
|
|
self.assertIn("ShardingTaskExecutorPoolMinSize", param_names_to_set)
|
|
|
|
|
self.assertIn("ingressAdmissionControlEnabled", param_names_to_set)
|
|
|
|
|
self.assert_parameter_values_ok(mongod_spec, ret)
|
|
|
|
|
|
|
|
|
|
def test_runtime_param_spec_validation(self):
|
|
|
|
|
bad_spec_value_not_dict = {"fakeRuntimeParam": 1}
|
|
|
|
|
bad_spec_value_no_period = {"fakeRuntimeParam": {"max": 50, "min": 10}}
|
|
|
|
|
good_spec = {"fakeRuntimeParam": {"max": 50, "min": 10, "period": 5}}
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
|
_runtime_fuzzer.validate_runtime_parameter_spec(bad_spec_value_not_dict)
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(ValueError):
|
|
|
|
|
_runtime_fuzzer.validate_runtime_parameter_spec(bad_spec_value_no_period)
|
|
|
|
|
# No exception for good dict
|
|
|
|
|
_runtime_fuzzer.validate_runtime_parameter_spec(good_spec)
|