blob: 17801c34523f5a910bd85746a650341fa8758b20 [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
Alex Kleind1e9e5c2020-12-14 12:32:32 -070093 @property
94 def run_endpoint(self) -> bool:
95 """Run the endpoint when none of the special calls are invoked."""
96 return (not self.validate_only and not self.mock_call and
97 not self.mock_error and not self.mock_invalid)
98
Alex Kleind815ca62020-01-10 12:21:30 -070099 def get_proto(self, for_inside_execution=True):
100 """Get the config as a proto.
101
102 Args:
103 for_inside_execution (bool): Allows avoiding propagating configs that are
104 irrelevant for the build api process executed inside the chroot.
105 Enabled by default.
106
107 Returns:
108 build_api_config_pb2.BuildApiConfig
109 """
110 config = build_api_config_pb2.BuildApiConfig()
111 config.call_type = self.ENUM_TYPE_MAP[self._call_type]
112
113 if not for_inside_execution:
114 # Add values not needed when reexecuting.
115 config.log_path = self.log_path
116
117 return config
118
119
120def build_config_from_proto(config_proto):
121 """Build an ApiConfig instance from a BuildApiConfig message.
122
123 Args:
124 config_proto (build_api_config_pb2.BuildApiConfig): The proto config.
125
126 Returns:
127 ApiConfig
128 """
129 assert isinstance(config_proto, build_api_config_pb2.BuildApiConfig)
130
131 if config_proto.call_type not in ApiConfig.TYPE_ENUM_MAP:
132 raise UnknownCallTypeEnumValue('The given protobuf call_type value is not '
133 'configured in api_config.')
134 return ApiConfig(call_type=ApiConfig.TYPE_ENUM_MAP[config_proto.call_type],
135 log_path=config_proto.log_path)
Alex Klein69339cc2019-07-22 14:08:35 -0600136
137
138class ApiConfigMixin(object):
139 """Mixin to add an API Config factory properties.
140
141 This is meant to be used for tests to make these configs more uniform across
Alex Kleine191ed62020-02-27 15:59:55 -0700142 all the tests since there's very little to change anyway.
Alex Klein69339cc2019-07-22 14:08:35 -0600143 """
144
145 @property
146 def api_config(self):
Alex Klein2008aee2019-08-20 16:25:27 -0600147 return ApiConfig()
Alex Klein69339cc2019-07-22 14:08:35 -0600148
149 @property
150 def validate_only_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700151 return ApiConfig(call_type=ApiConfig.CALL_TYPE_VALIDATE_ONLY)
Alex Klein2008aee2019-08-20 16:25:27 -0600152
153 @property
154 def no_validate_config(self):
155 return self.mock_call_config
156
157 @property
158 def mock_call_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700159 return ApiConfig(call_type=ApiConfig.CALL_TYPE_MOCK_SUCCESS)
Alex Klein2008aee2019-08-20 16:25:27 -0600160
161 @property
162 def mock_error_config(self):
Alex Kleind815ca62020-01-10 12:21:30 -0700163 return ApiConfig(call_type=ApiConfig.CALL_TYPE_MOCK_FAILURE)