blob: 2e80d077b64335d1d6a4bab7a03ac788b0effcff [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
136 all of the tests since there's very little to change anyway.
137 """
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)