Adding upstream version 1.1.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 11:54:23 +01:00
parent f13b7abbd8
commit 77504588ab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
196 changed files with 10121 additions and 3780 deletions

View file

@ -0,0 +1,4 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Unit tests for the asynceapi client package used by ANTA."""

View file

@ -0,0 +1,20 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Fixtures for the asynceapi client package."""
import pytest
from asynceapi import Device
@pytest.fixture
def asynceapi_device() -> Device:
"""Return an asynceapi Device instance."""
return Device(
host="localhost",
username="admin",
password="admin",
proto="https",
port=443,
)

View file

@ -0,0 +1,88 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Unit tests data for the asynceapi client package."""
SUCCESS_EAPI_RESPONSE = {
"jsonrpc": "2.0",
"id": "EapiExplorer-1",
"result": [
{
"mfgName": "Arista",
"modelName": "cEOSLab",
"hardwareRevision": "",
"serialNumber": "5E9D49D20F09DA471333DD835835FD1A",
"systemMacAddress": "00:1c:73:2e:7b:a3",
"hwMacAddress": "00:00:00:00:00:00",
"configMacAddress": "00:00:00:00:00:00",
"version": "4.31.1F-34554157.4311F (engineering build)",
"architecture": "i686",
"internalVersion": "4.31.1F-34554157.4311F",
"internalBuildId": "47114ca4-ae9f-4f32-8c1f-2864db93b7e8",
"imageFormatVersion": "1.0",
"imageOptimization": "None",
"cEosToolsVersion": "(unknown)",
"kernelVersion": "6.5.0-44-generic",
"bootupTimestamp": 1723429239.9352903,
"uptime": 1300202.749528885,
"memTotal": 65832112,
"memFree": 41610316,
"isIntlVersion": False,
},
{
"utcTime": 1724729442.6863558,
"timezone": "EST",
"localTime": {
"year": 2024,
"month": 8,
"dayOfMonth": 26,
"hour": 22,
"min": 30,
"sec": 42,
"dayOfWeek": 0,
"dayOfYear": 239,
"daylightSavingsAdjust": 0,
},
"clockSource": {"local": True},
},
],
}
"""Successful eAPI JSON response."""
ERROR_EAPI_RESPONSE = {
"jsonrpc": "2.0",
"id": "EapiExplorer-1",
"error": {
"code": 1002,
"message": "CLI command 2 of 3 'bad command' failed: invalid command",
"data": [
{
"mfgName": "Arista",
"modelName": "cEOSLab",
"hardwareRevision": "",
"serialNumber": "5E9D49D20F09DA471333DD835835FD1A",
"systemMacAddress": "00:1c:73:2e:7b:a3",
"hwMacAddress": "00:00:00:00:00:00",
"configMacAddress": "00:00:00:00:00:00",
"version": "4.31.1F-34554157.4311F (engineering build)",
"architecture": "i686",
"internalVersion": "4.31.1F-34554157.4311F",
"internalBuildId": "47114ca4-ae9f-4f32-8c1f-2864db93b7e8",
"imageFormatVersion": "1.0",
"imageOptimization": "None",
"cEosToolsVersion": "(unknown)",
"kernelVersion": "6.5.0-44-generic",
"bootupTimestamp": 1723429239.9352903,
"uptime": 1300027.2297976017,
"memTotal": 65832112,
"memFree": 41595080,
"isIntlVersion": False,
},
{"errors": ["Invalid input (at token 1: 'bad')"]},
],
},
}
"""Error eAPI JSON response."""
JSONRPC_REQUEST_TEMPLATE = {"jsonrpc": "2.0", "method": "runCmds", "params": {"version": 1, "cmds": [], "format": "json"}, "id": "EapiExplorer-1"}
"""Template for JSON-RPC eAPI request. `cmds` must be filled by the parametrize decorator."""

View file

@ -0,0 +1,85 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Unit tests the asynceapi.device module."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import pytest
from httpx import HTTPStatusError
from asynceapi import Device, EapiCommandError
from .test_data import ERROR_EAPI_RESPONSE, JSONRPC_REQUEST_TEMPLATE, SUCCESS_EAPI_RESPONSE
if TYPE_CHECKING:
from pytest_httpx import HTTPXMock
@pytest.mark.parametrize(
"cmds",
[
(["show version", "show clock"]),
([{"cmd": "show version"}, {"cmd": "show clock"}]),
([{"cmd": "show version"}, "show clock"]),
],
ids=["simple_commands", "complex_commands", "mixed_commands"],
)
async def test_jsonrpc_exec_success(
asynceapi_device: Device,
httpx_mock: HTTPXMock,
cmds: list[str | dict[str, Any]],
) -> None:
"""Test the Device.jsonrpc_exec method with a successful response. Simple and complex commands are tested."""
jsonrpc_request: dict[str, Any] = JSONRPC_REQUEST_TEMPLATE.copy()
jsonrpc_request["params"]["cmds"] = cmds
httpx_mock.add_response(json=SUCCESS_EAPI_RESPONSE)
result = await asynceapi_device.jsonrpc_exec(jsonrpc=jsonrpc_request)
assert result == SUCCESS_EAPI_RESPONSE["result"]
@pytest.mark.parametrize(
"cmds",
[
(["show version", "bad command", "show clock"]),
([{"cmd": "show version"}, {"cmd": "bad command"}, {"cmd": "show clock"}]),
([{"cmd": "show version"}, {"cmd": "bad command"}, "show clock"]),
],
ids=["simple_commands", "complex_commands", "mixed_commands"],
)
async def test_jsonrpc_exec_eapi_command_error(
asynceapi_device: Device,
httpx_mock: HTTPXMock,
cmds: list[str | dict[str, Any]],
) -> None:
"""Test the Device.jsonrpc_exec method with an error response. Simple and complex commands are tested."""
jsonrpc_request: dict[str, Any] = JSONRPC_REQUEST_TEMPLATE.copy()
jsonrpc_request["params"]["cmds"] = cmds
error_eapi_response: dict[str, Any] = ERROR_EAPI_RESPONSE.copy()
httpx_mock.add_response(json=error_eapi_response)
with pytest.raises(EapiCommandError) as exc_info:
await asynceapi_device.jsonrpc_exec(jsonrpc=jsonrpc_request)
assert exc_info.value.passed == [error_eapi_response["error"]["data"][0]]
assert exc_info.value.failed == "bad command"
assert exc_info.value.errors == ["Invalid input (at token 1: 'bad')"]
assert exc_info.value.errmsg == "CLI command 2 of 3 'bad command' failed: invalid command"
assert exc_info.value.not_exec == [jsonrpc_request["params"]["cmds"][2]]
async def test_jsonrpc_exec_http_status_error(asynceapi_device: Device, httpx_mock: HTTPXMock) -> None:
"""Test the Device.jsonrpc_exec method with an HTTPStatusError."""
jsonrpc_request: dict[str, Any] = JSONRPC_REQUEST_TEMPLATE.copy()
jsonrpc_request["params"]["cmds"] = ["show version"]
httpx_mock.add_response(status_code=500, text="Internal Server Error")
with pytest.raises(HTTPStatusError):
await asynceapi_device.jsonrpc_exec(jsonrpc=jsonrpc_request)