blob: a26f5fa1f709f9c6ebbcd299573a06f94eca3a22 [file] [log] [blame]
Alex Klein69339cc2019-07-22 14:08:35 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Alex Klein2008aee2019-08-20 16:25:27 -06006"""API config object and related helper functionality."""
Alex Klein69339cc2019-07-22 14:08:35 -06007
8from __future__ import print_function
9
Mike Frysingeref94e4c2020-02-10 23:59:54 -050010import sys
11
Alex Kleind815ca62020-01-10 12:21:30 -070012from chromite.api.gen.chromite.api import build_api_config_pb2
13
14
Mike Frysingeref94e4c2020-02-10 23:59:54 -050015assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
16
17
Alex Kleind815ca62020-01-10 12:21:30 -070018class Error(Exception):
19 """Base error class for the module."""
20
21
22class UnknownCallTypeEnumValue(Error):
23 """Thrown when the call type enum value in proto is not configured here."""
24
Alex Klein69339cc2019-07-22 14:08:35 -060025
Alex Klein2008aee2019-08-20 16:25:27 -060026class ApiConfig(object):
27 """API Config class."""
Alex Kleind815ca62020-01-10 12:21:30 -070028 # Call type constants.
29 CALL_TYPE_EXECUTE = 1
30 CALL_TYPE_VALIDATE_ONLY = 2
31 CALL_TYPE_MOCK_SUCCESS = 3
32 CALL_TYPE_MOCK_FAILURE = 4
33 CALL_TYPE_MOCK_INVALID = 5
Alex Klein69339cc2019-07-22 14:08:35 -060034
Alex Kleind815ca62020-01-10 12:21:30 -070035 # Maps the proto enum to the type constants.
36 TYPE_ENUM_MAP = {
37 build_api_config_pb2.CALL_TYPE_NONE: CALL_TYPE_EXECUTE,
38 build_api_config_pb2.CALL_TYPE_EXECUTE: CALL_TYPE_EXECUTE,
39 build_api_config_pb2.CALL_TYPE_VALIDATE_ONLY: CALL_TYPE_VALIDATE_ONLY,
40 build_api_config_pb2.CALL_TYPE_MOCK_SUCCESS: CALL_TYPE_MOCK_SUCCESS,
41 build_api_config_pb2.CALL_TYPE_MOCK_FAILURE: CALL_TYPE_MOCK_FAILURE,
42 build_api_config_pb2.CALL_TYPE_MOCK_INVALID: CALL_TYPE_MOCK_INVALID,
43 }
44
45 # Maps the type constants to the proto enums.
46 ENUM_TYPE_MAP = {
47 CALL_TYPE_EXECUTE: build_api_config_pb2.CALL_TYPE_EXECUTE,
48 CALL_TYPE_VALIDATE_ONLY: build_api_config_pb2.CALL_TYPE_VALIDATE_ONLY,
49 CALL_TYPE_MOCK_SUCCESS: build_api_config_pb2.CALL_TYPE_MOCK_SUCCESS,
50 CALL_TYPE_MOCK_FAILURE: build_api_config_pb2.CALL_TYPE_MOCK_FAILURE,
51 CALL_TYPE_MOCK_INVALID: build_api_config_pb2.CALL_TYPE_MOCK_INVALID,
52 }
53
54 # The valid call types.
55 _VALID_CALL_TYPES = tuple(ENUM_TYPE_MAP.keys())
56
57 def __init__(self, call_type=CALL_TYPE_EXECUTE, log_path=None):
58 assert call_type in self._VALID_CALL_TYPES
59 self._call_type = call_type
60 # Explicit `or None` to simplify proto default empty string.
61 self.log_path = log_path or None
Alex Klein2008aee2019-08-20 16:25:27 -060062
63 def __eq__(self, other):
64 if self.__class__ is other.__class__:
Alex Kleind815ca62020-01-10 12:21:30 -070065 return self.__dict__ == other.__dict__
Alex Klein2008aee2019-08-20 16:25:27 -060066
67 return NotImplemented
68
69 __hash__ = NotImplemented
70
71 @property
72 def do_validation(self):
Alex Kleind815ca62020-01-10 12:21:30 -070073 # We skip validation for all mock calls, so do validation when it's
74 # anything but a mocked call.
75 return not (self.mock_call or self.mock_error or self.mock_invalid)
76
77 @property
78 def validate_only(self):
79 return self._call_type == self.CALL_TYPE_VALIDATE_ONLY
80
81 @property
82 def mock_call(self):
83 return self._call_type == self.CALL_TYPE_MOCK_SUCCESS
84
85 @property
86 def mock_error(self):
87 return self._call_type == self.CALL_TYPE_MOCK_FAILURE
88
89 @property
90 def mock_invalid(self):
91 return self._call_type == self.CALL_TYPE_MOCK_INVALID
92
93 def get_proto(self, for_inside_execution=True):
94 """Get the config as a proto.
95
96 Args:
97 for_inside_execution (bool): Allows avoiding propagating configs that are
98 irrelevant for the build api process executed inside the chroot.
99 Enabled by default.
100
101 Returns:
102 build_api_config_pb2.BuildApiConfig
103 """
104 config = build_api_config_pb2.BuildApiConfig()
105 config.call_type = self.ENUM_TYPE_MAP[self._call_type]
106
107 if not for_inside_execution:
108 # Add values not needed when reexecuting.
109 config.log_path = self.log_path
110
111 return config
112
113
114def build_config_from_proto(config_proto):
115 """Build an ApiConfig instance from a BuildApiConfig message.
116
117 Args:
118 config_proto (build_api_config_pb2.BuildApiConfig): The proto config.
119
120 Returns:
121 ApiConfig
122 """
123 assert isinstance(config_proto, build_api_config_pb2.BuildApiConfig)
124
125 if config_proto.call_type not in ApiConfig.TYPE_ENUM_MAP:
126 raise UnknownCallTypeEnumValue('The given protobuf call_type value is not '
127 'configured in api_config.')
128 return ApiConfig(call_type=ApiConfig.TYPE_ENUM_MAP[config_proto.call_type],
129 log_path=config_proto.log_path)
Alex Klein69339cc2019-07-22 14:08:35 -0600130
131
132class ApiConfigMixin(object):
133 """Mixin to add an API Config factory properties.
134
135 This is meant to be used for tests to make these configs more uniform across
Alex Kleine191ed62020-02-27 15:59:55 -0700136 all the tests since there's very little to change anyway.
Alex Klein69339cc2019-07-22 14:08:35 -0600137 """
138
139 @property
140 def api_config(self):
Alex Klein2008aee2019-08-20 16:25:27 -0600141 return ApiConfig()
Alex Klein69339cc2019-07-22 14:08:35 -0600142
143 @property
144 def validate_only_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700145 return ApiConfig(call_type=ApiConfig.CALL_TYPE_VALIDATE_ONLY)
Alex Klein2008aee2019-08-20 16:25:27 -0600146
147 @property
148 def no_validate_config(self):
149 return self.mock_call_config
150
151 @property
152 def mock_call_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700153 return ApiConfig(call_type=ApiConfig.CALL_TYPE_MOCK_SUCCESS)
Alex Klein2008aee2019-08-20 16:25:27 -0600154
155 @property
156 def mock_error_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700157 return ApiConfig(call_type=ApiConfig.CALL_TYPE_MOCK_FAILURE)