blob: 085c587393d4b483120064382d31eb77025c9ff3 [file] [log] [blame]
# Copyright 2020 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.
"""Defines ConstraintSuite, which is subclassed to define constraints."""
import inspect
from bindings.src.config.api import config_bundle_pb2
class InvalidConstraintSuiteError(Exception):
"""Exception raised when an invalid ConstraintSuite is defined."""
class ConstraintSuite:
"""A class whose instances are suites of constraints.
Constraint authors should subclass ConstraintSuite and add methods starting
with "check" for each constraint they want to enforce. Each check method
should accept two ConfigBundles, with parameter names "project_config" and
"program_config". A check method is considered failed iff it raises an
Exception.
A ConstraintSuite subclass should group related constraints. For example a
suite to check form factor constraints could look like:
class FormFactorConstraintSuite(ConstraintSuite):
def checkFormFactorDefined(self, program_config, project_config):
...
def checkFormFactorAllowedByProgram(self, program_config, project_config):
...
A ConstraintSuite that defines no check methods will raise an exception on
initialization.
"""
def __init__(self):
super().__init__()
def is_check(name, value):
return name.startswith('check') and inspect.ismethod(value)
self._checks = [
value for name, value in inspect.getmembers(self)
if is_check(name, value)
]
if not self._checks:
raise InvalidConstraintSuiteError('No checks found on %s' % type(self))
def run_checks(self, program_config: config_bundle_pb2.ConfigBundle,
project_config: config_bundle_pb2.ConfigBundle):
"""Runs all of the checks on an instance.
Args:
program_config: The program's config, to pass to each check.
project_config: The project's config, to pass to each check.
"""
for method in self._checks:
method(program_config=program_config, project_config=project_config)