blob: fdec6478654c535bb77e659d770032139c25a70b [file] [log] [blame]
# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Decorators to help handle mock calls and errors in the Build API."""
import functools
from typing import Any, Callable, Dict, Iterable, TYPE_CHECKING
from chromite.api import controller
if TYPE_CHECKING:
from chromite.third_party.google.protobuf import message as protobuf_message
from chromite.api import api_config
BuildAPIFunction = Callable[
[
"protobuf_message.Message",
"protobuf_message.Message",
"api_config.ApiConfig",
Iterable[Any],
Dict[Any, Any],
],
int,
]
def all_responses(
faux_result_factory: BuildAPIFunction,
) -> Callable[[BuildAPIFunction], BuildAPIFunction,]:
"""A decorator to handle all mock responses.
This is syntactic sugar for handling all the mock response types in a
single function.
Args:
faux_result_factory: A function with the same signature as a regular
API endpoint function that populates the output with success or
error results, as requested, without executing the endpoint.
"""
# Get the decorators for each of the mock types, so we can compose them.
success_fn = success(faux_result_factory)
err_fn = error(faux_result_factory)
def _decorator(func: BuildAPIFunction) -> BuildAPIFunction:
f = success_fn(func)
return err_fn(f)
return _decorator
def all_empty(func: BuildAPIFunction) -> BuildAPIFunction:
"""Decorator to handle all mock responses with an empty output."""
return empty_error(empty_success(func))
def success(
faux_result_factory: BuildAPIFunction,
) -> Callable[[BuildAPIFunction], BuildAPIFunction,]:
"""A decorator to handle mock call responses.
Args:
faux_result_factory: A function with the same signature as a regular
API endpoint function that populates the output
"""
def decorator(func: BuildAPIFunction) -> BuildAPIFunction:
@functools.wraps(func)
def _success(
request: "protobuf_message.Message",
response: "protobuf_message.Message",
config: "api_config.ApiConfig",
*args: Any,
**kwargs: Any,
) -> int:
if config.mock_call:
faux_result_factory(request, response, config, *args, **kwargs)
return controller.RETURN_CODE_SUCCESS
return func(request, response, config, *args, **kwargs)
return _success
return decorator
def empty_success(func: BuildAPIFunction) -> BuildAPIFunction:
"""A decorator to handle mock success responses with empty outputs."""
@functools.wraps(func)
def _empty_success(
request: "protobuf_message.Message",
response: "protobuf_message.Message",
config: "api_config.ApiConfig",
*args: Any,
**kwargs: Any,
) -> int:
if config.mock_call:
return controller.RETURN_CODE_SUCCESS
return func(request, response, config, *args, **kwargs)
return _empty_success
def error(
faux_error_factory: BuildAPIFunction,
) -> Callable[[BuildAPIFunction], BuildAPIFunction,]:
"""A decorator to handle mock error responses."""
def decorator(func: BuildAPIFunction) -> BuildAPIFunction:
@functools.wraps(func)
def _error(
request: "protobuf_message.Message",
response: "protobuf_message.Message",
config: "api_config.ApiConfig",
*args: Any,
**kwargs: Any,
) -> int:
if config.mock_error:
faux_error_factory(request, response, config, *args, **kwargs)
return controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE
return func(request, response, config, *args, **kwargs)
return _error
return decorator
def empty_error(func: BuildAPIFunction) -> BuildAPIFunction:
"""A decorator to handle mock error responses with empty outputs."""
@functools.wraps(func)
def _empty_error(
request: "protobuf_message.Message",
response: "protobuf_message.Message",
config: "api_config.ApiConfig",
*args: Any,
**kwargs: Any,
) -> int:
if config.mock_error:
return controller.RETURN_CODE_UNRECOVERABLE
return func(request, response, config, *args, **kwargs)
return _empty_error
def empty_completed_unsuccessfully_error(
func: BuildAPIFunction,
) -> BuildAPIFunction:
"""A decorator to handle mock unsuccessful response with empty outputs."""
@functools.wraps(func)
def _empty_error(
request: "protobuf_message.Message",
response: "protobuf_message.Message",
config: "api_config.ApiConfig",
*args: Any,
**kwargs: Any,
) -> int:
if config.mock_error:
return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
return func(request, response, config, *args, **kwargs)
return _empty_error