mirror of
https://github.com/thatmattlove/hyperglass.git
synced 2026-01-17 08:48:05 +00:00
fix issues causing test failure
This commit is contained in:
parent
92bc28ac05
commit
99ec07d055
10 changed files with 104 additions and 32 deletions
|
|
@ -1,4 +1,5 @@
|
|||
"""hyperglass Configuration."""
|
||||
|
||||
# Standard Library
|
||||
import typing as t
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ class HyperglassError(Exception):
|
|||
return template.format(**kwargs)
|
||||
|
||||
def _parse_pydantic_errors(*errors: Dict[str, Any]) -> str:
|
||||
|
||||
errs = ("\n",)
|
||||
|
||||
for err in errors:
|
||||
|
|
@ -121,10 +120,16 @@ class PublicHyperglassError(HyperglassError):
|
|||
|
||||
def __init__(self, **kwargs: str) -> None:
|
||||
"""Format error message with keyword arguments."""
|
||||
from hyperglass.state import use_state
|
||||
|
||||
if "error" in kwargs:
|
||||
error = kwargs.pop("error")
|
||||
error = self._safe_format(str(error), **kwargs)
|
||||
kwargs["error"] = error
|
||||
|
||||
(messages := use_state("params").messages)
|
||||
if messages.has(self._message_template):
|
||||
self._message_template = messages[self._message_template]
|
||||
self._message = self._safe_format(self._message_template, **kwargs)
|
||||
self._keywords = list(kwargs.values())
|
||||
super().__init__(message=self._message, level=self._level, keywords=self._keywords)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
# Standard Library
|
||||
from typing import TYPE_CHECKING, Any, Dict, Optional
|
||||
|
||||
# Project
|
||||
from hyperglass.state import use_state
|
||||
|
||||
# Local
|
||||
from ._common import PublicHyperglassError
|
||||
|
|
@ -14,13 +12,10 @@ if TYPE_CHECKING:
|
|||
from hyperglass.models.api.query import Query
|
||||
from hyperglass.models.config.devices import Device
|
||||
|
||||
(MESSAGES := use_state("params").messages)
|
||||
(TEXT := use_state("params").web.text)
|
||||
|
||||
|
||||
class ScrapeError(
|
||||
PublicHyperglassError,
|
||||
template=MESSAGES.connection_error,
|
||||
template="connection_error",
|
||||
level="danger",
|
||||
):
|
||||
"""Raised when an SSH driver error occurs."""
|
||||
|
|
@ -30,7 +25,7 @@ class ScrapeError(
|
|||
super().__init__(error=str(error), device=device.name, proxy=device.proxy)
|
||||
|
||||
|
||||
class AuthError(PublicHyperglassError, template=MESSAGES.authentication_error, level="danger"):
|
||||
class AuthError(PublicHyperglassError, template="authentication_error", level="danger"):
|
||||
"""Raised when authentication to a device fails."""
|
||||
|
||||
def __init__(self, *, error: BaseException, device: "Device"):
|
||||
|
|
@ -38,7 +33,7 @@ class AuthError(PublicHyperglassError, template=MESSAGES.authentication_error, l
|
|||
super().__init__(error=str(error), device=device.name, proxy=device.proxy)
|
||||
|
||||
|
||||
class RestError(PublicHyperglassError, template=MESSAGES.connection_error, level="danger"):
|
||||
class RestError(PublicHyperglassError, template="connection_error", level="danger"):
|
||||
"""Raised upon a rest API client error."""
|
||||
|
||||
def __init__(self, *, error: BaseException, device: "Device"):
|
||||
|
|
@ -46,7 +41,7 @@ class RestError(PublicHyperglassError, template=MESSAGES.connection_error, level
|
|||
super().__init__(error=str(error), device=device.name)
|
||||
|
||||
|
||||
class DeviceTimeout(PublicHyperglassError, template=MESSAGES.request_timeout, level="danger"):
|
||||
class DeviceTimeout(PublicHyperglassError, template="request_timeout", level="danger"):
|
||||
"""Raised when the connection to a device times out."""
|
||||
|
||||
def __init__(self, *, error: BaseException, device: "Device"):
|
||||
|
|
@ -54,7 +49,7 @@ class DeviceTimeout(PublicHyperglassError, template=MESSAGES.request_timeout, le
|
|||
super().__init__(error=str(error), device=device.name, proxy=device.proxy)
|
||||
|
||||
|
||||
class InvalidQuery(PublicHyperglassError, template=MESSAGES.invalid_query):
|
||||
class InvalidQuery(PublicHyperglassError, template="request_timeout"):
|
||||
"""Raised when input validation fails."""
|
||||
|
||||
def __init__(
|
||||
|
|
@ -74,7 +69,7 @@ class InvalidQuery(PublicHyperglassError, template=MESSAGES.invalid_query):
|
|||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class NotFound(PublicHyperglassError, template=MESSAGES.not_found):
|
||||
class NotFound(PublicHyperglassError, template="not_found"):
|
||||
"""Raised when an object is not found."""
|
||||
|
||||
def __init__(self, type: str, name: str, **kwargs: Dict[str, str]) -> None:
|
||||
|
|
@ -87,8 +82,11 @@ class QueryLocationNotFound(NotFound):
|
|||
|
||||
def __init__(self, location: Any, **kwargs: Dict[str, Any]) -> None:
|
||||
"""Initialize a NotFound error for a query location."""
|
||||
from hyperglass.state import use_state
|
||||
|
||||
super().__init__(type=TEXT.query_location, name=str(location), **kwargs)
|
||||
(text := use_state("params").web.text)
|
||||
|
||||
super().__init__(type=text.query_location, name=str(location), **kwargs)
|
||||
|
||||
|
||||
class QueryTypeNotFound(NotFound):
|
||||
|
|
@ -96,10 +94,13 @@ class QueryTypeNotFound(NotFound):
|
|||
|
||||
def __init__(self, query_type: Any, **kwargs: Dict[str, Any]) -> None:
|
||||
"""Initialize a NotFound error for a query type."""
|
||||
super().__init__(type=TEXT.query_type, name=str(query_type), **kwargs)
|
||||
from hyperglass.state import use_state
|
||||
|
||||
(text := use_state("params").web.text)
|
||||
super().__init__(type=text.query_type, name=str(query_type), **kwargs)
|
||||
|
||||
|
||||
class InputInvalid(PublicHyperglassError, template=MESSAGES.invalid_input):
|
||||
class InputInvalid(PublicHyperglassError, template="invalid_input"):
|
||||
"""Raised when input validation fails."""
|
||||
|
||||
def __init__(
|
||||
|
|
@ -115,7 +116,7 @@ class InputInvalid(PublicHyperglassError, template=MESSAGES.invalid_input):
|
|||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class InputNotAllowed(PublicHyperglassError, template=MESSAGES.target_not_allowed):
|
||||
class InputNotAllowed(PublicHyperglassError, template="target_not_allowed"):
|
||||
"""Raised when input validation fails due to a configured check."""
|
||||
|
||||
def __init__(
|
||||
|
|
@ -135,7 +136,7 @@ class InputNotAllowed(PublicHyperglassError, template=MESSAGES.target_not_allowe
|
|||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class ResponseEmpty(PublicHyperglassError, template=MESSAGES.no_output):
|
||||
class ResponseEmpty(PublicHyperglassError, template="no_output"):
|
||||
"""Raised when hyperglass can connect to the device but the response is empty."""
|
||||
|
||||
def __init__(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
# Project
|
||||
from hyperglass.models.api import Query
|
||||
from hyperglass.configuration import init_user_config
|
||||
from hyperglass.models.directive import Directives
|
||||
from hyperglass.models.config.devices import Devices
|
||||
from hyperglass.state import use_state
|
||||
from hyperglass.test import initialize_state
|
||||
|
||||
# Local
|
||||
from .._construct import Construct
|
||||
|
||||
|
||||
def test_construct():
|
||||
|
||||
devices = Devices(
|
||||
devices = [
|
||||
{
|
||||
"name": "test1",
|
||||
"address": "127.0.0.1",
|
||||
|
|
@ -19,15 +17,24 @@ def test_construct():
|
|||
"attrs": {"source4": "192.0.2.1", "source6": "2001:db8::1"},
|
||||
"directives": ["juniper_bgp_route"],
|
||||
}
|
||||
)
|
||||
directives = Directives(
|
||||
{"juniper_bgp_route": {"name": "BGP Route", "plugins": [], "rules": [], "groups": []}}
|
||||
)
|
||||
init_user_config(devices=devices, directives=directives)
|
||||
]
|
||||
directives = [
|
||||
{
|
||||
"juniper_bgp_route": {
|
||||
"name": "BGP Route",
|
||||
"field": {"description": "test"},
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
initialize_state(params={}, directives=directives, devices=devices)
|
||||
|
||||
state = use_state()
|
||||
|
||||
query = Query(
|
||||
queryLocation="test1",
|
||||
queryTarget="192.0.2.0/24",
|
||||
queryType="juniper_bgp_route",
|
||||
)
|
||||
constructor = Construct(device=devices["test1"], query=query)
|
||||
constructor = Construct(device=state.devices["test1"], query=query)
|
||||
assert constructor.target == "192.0.2.0/24"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ from hyperglass.exceptions.private import InputValidationError
|
|||
# Local
|
||||
from ..config.devices import Device
|
||||
|
||||
(TEXT := use_state("params").web.text)
|
||||
|
||||
QueryLocation = constr(strip_whitespace=True, strict=True, min_length=1)
|
||||
QueryTarget = constr(strip_whitespace=True, min_length=1)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ class Device(HyperglassModelWithId, extra="allow"):
|
|||
return self.platform
|
||||
|
||||
def _validate_directive_attrs(self) -> None:
|
||||
|
||||
# Set of all keys except for built-in key `target`.
|
||||
keys = {
|
||||
key
|
||||
|
|
|
|||
|
|
@ -75,6 +75,17 @@ class Messages(HyperglassModel):
|
|||
description="Displayed when hyperglass can connect to a device and execute a query, but the response is empty.",
|
||||
)
|
||||
|
||||
def has(self, attr: str) -> bool:
|
||||
"""Determine if message type exists in Messages model."""
|
||||
return attr in self.dict().keys()
|
||||
|
||||
def __getitem__(self, attr: str) -> StrictStr:
|
||||
"""Make messages subscriptable."""
|
||||
|
||||
if not self.has(attr):
|
||||
raise KeyError(f"'{attr}' does not exist on Messages model")
|
||||
return getattr(self, attr)
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
|
|
|
|||
|
|
@ -253,8 +253,8 @@ class Directive(HyperglassUniqueModel, unique_by=("id", "table_output")):
|
|||
|
||||
id: StrictStr
|
||||
name: StrictStr
|
||||
rules: t.List[RuleType]
|
||||
field: t.Union[Text, Select, None]
|
||||
rules: t.List[RuleType] = [RuleWithPattern(condition="*")]
|
||||
field: t.Union[Text, Select]
|
||||
info: t.Optional[FilePath]
|
||||
plugins: t.List[StrictStr] = []
|
||||
table_output: t.Optional[StrictStr]
|
||||
|
|
@ -350,3 +350,13 @@ class Directives(MultiModel[Directive], model=Directive, unique_by="id"):
|
|||
if _directive.id == directive.table_output:
|
||||
return _directive
|
||||
return directive
|
||||
|
||||
@classmethod
|
||||
def new(cls, /, *raw_directives: t.Dict[str, t.Any]) -> "Directives":
|
||||
"""Create a new Directives collection from raw directive configurations."""
|
||||
directives = (
|
||||
Directive(id=name, **directive)
|
||||
for raw_directive in raw_directives
|
||||
for name, directive in raw_directive.items()
|
||||
)
|
||||
return Directives(*directives)
|
||||
|
|
|
|||
4
hyperglass/test/__init__.py
Normal file
4
hyperglass/test/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
"""Global test helpers."""
|
||||
from .state import initialize_state
|
||||
|
||||
__all__ = ("initialize_state",)
|
||||
35
hyperglass/test/state.py
Normal file
35
hyperglass/test/state.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""State-related test helpers."""
|
||||
|
||||
import typing as t
|
||||
|
||||
from hyperglass.state import use_state
|
||||
from hyperglass.models.config.params import Params
|
||||
from hyperglass.models.config.devices import Devices
|
||||
from hyperglass.models.directive import Directives
|
||||
from hyperglass.configuration import init_ui_params
|
||||
|
||||
|
||||
def initialize_state(
|
||||
*,
|
||||
params: t.Dict[str, t.Any],
|
||||
directives: t.Sequence[t.Dict[str, t.Any]],
|
||||
devices: t.Sequence[t.Dict[str, t.Any]],
|
||||
) -> None:
|
||||
"""Test fixture to initialize Redis store."""
|
||||
state = use_state()
|
||||
_params = Params(**params)
|
||||
_directives = Directives.new(*directives)
|
||||
|
||||
with state.cache.pipeline() as pipeline:
|
||||
# Write params and directives to the cache first to avoid a race condition where ui_params
|
||||
# or devices try to access params or directives before they're available.
|
||||
pipeline.set("params", _params)
|
||||
pipeline.set("directives", _directives)
|
||||
|
||||
# _devices = Devices.new(*devices)
|
||||
_devices = Devices(*devices)
|
||||
ui_params = init_ui_params(params=_params, devices=_devices)
|
||||
|
||||
with state.cache.pipeline() as pipeline:
|
||||
pipeline.set("devices", _devices)
|
||||
pipeline.set("ui_params", ui_params)
|
||||
Loading…
Add table
Reference in a new issue