Skip to content

Commit

Permalink
More types (#287)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea authored Aug 27, 2024
1 parent e67d544 commit eb8db79
Show file tree
Hide file tree
Showing 21 changed files with 201 additions and 125 deletions.
5 changes: 3 additions & 2 deletions extensions/eda/plugins/event_source/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"""

import pathlib
from typing import Union
from asyncio import Queue
from typing import Any, Union

import yaml
from watchdog.events import FileSystemEvent, RegexMatchingEventHandler
Expand Down Expand Up @@ -98,7 +99,7 @@ def on_moved(self: "Handler", event: FileSystemEvent) -> None:
if __name__ == "__main__":
"""MockQueue if running directly."""

class MockQueue:
class MockQueue(Queue[Any]):
"""A fake queue."""

async def put(self: "MockQueue", event: dict) -> None:
Expand Down
2 changes: 1 addition & 1 deletion extensions/eda/plugins/event_source/file_watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def watch(
class Handler(RegexMatchingEventHandler):
"""A handler for file system events."""

def __init__(self: "Handler", **kwargs) -> None:
def __init__(self: "Handler", **kwargs: Any) -> None:
RegexMatchingEventHandler.__init__(self, **kwargs)

def on_created(self: "Handler", event: FileSystemEvent) -> None:
Expand Down
10 changes: 9 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ error_summary = true
# TODO: Remove temporary skips and close https://github.com/ansible/event-driven-ansible/issues/258
# strict = true
# disallow_untyped_calls = true
# disallow_untyped_defs = true
disallow_untyped_defs = true
# disallow_any_generics = true
# disallow_any_unimported = True
# warn_redundant_casts = True
Expand All @@ -65,6 +65,14 @@ module = [
]
ignore_missing_imports = true

# TODO: Remove as part of https://github.com/ansible/event-driven-ansible/issues/258
[[tool.mypy.overrides]]
module = [
"plugins.module_utils.controller",
"extensions.eda.plugins.event_source.file"
]
disallow_untyped_defs = false

[tool.pylint.MASTER]
# Temporary ignore until we are able to address issues on these:
ignore-paths = "^(demos/dynatrace-demo/fake_app.py|tests/|plugins/modules).*$"
Expand Down
10 changes: 5 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class ListQueue(asyncio.Queue[Any]):
def __init__(self) -> None:
self.queue: list[Any] = []

async def put(self, event) -> None:
self.queue.append(event)
async def put(self, item: Any) -> None:
self.queue.append(item)

def put_nowait(self, event) -> None:
self.queue.append(event)
def put_nowait(self, item: Any) -> None:
self.queue.append(item)


@pytest.fixture
def eda_queue():
def eda_queue() -> ListQueue:
return ListQueue()
12 changes: 8 additions & 4 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from subprocess import Popen
from typing import Callable, Iterator

import pytest


@pytest.fixture(scope="function")
def subprocess_teardown():
processes = []
def subprocess_teardown() -> Iterator[Callable]:
processes: list[Popen[bytes]] = []

def _teardown(process) -> None:
def _teardown(process: Popen[bytes]) -> None:
processes.append(process)

yield _teardown
[proc.terminate() for proc in processes]
for proc in processes:
proc.terminate()
40 changes: 32 additions & 8 deletions tests/integration/event_source_kafka/test_kafka_source.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import os
import subprocess
from typing import Any, Generator

import pytest
from kafka import KafkaProducer
Expand All @@ -9,7 +10,7 @@


@pytest.fixture(scope="session")
def kafka_certs():
def kafka_certs() -> Generator[subprocess.CompletedProcess[bytes], None, None]:
cwd = os.path.join(TESTS_PATH, "event_source_kafka")
print(cwd)
result = subprocess.run([os.path.join(cwd, "certs-create.sh")], cwd=cwd, check=True)
Expand All @@ -18,7 +19,7 @@ def kafka_certs():


@pytest.fixture(scope="session")
def kafka_broker():
def kafka_broker() -> Generator[subprocess.CompletedProcess[bytes], None, None]:
cwd = os.path.join(TESTS_PATH, "event_source_kafka")
print(cwd)
# Keep --quiet-pull here is it does spam CI/CD console
Expand All @@ -30,12 +31,19 @@ def kafka_broker():


@pytest.fixture(scope="session")
def kafka_producer(kafka_certs, kafka_broker):
def kafka_producer(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
) -> KafkaProducer:
return KafkaProducer(bootstrap_servers="localhost:9092")


@pytest.mark.xfail(reason="https://github.com/ansible/event-driven-ansible/issues/234")
def test_kafka_source_plaintext(kafka_certs, kafka_broker, kafka_producer) -> None:
def test_kafka_source_plaintext(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
kafka_producer: Any,
) -> None:
ruleset = os.path.join(
TESTS_PATH, "event_source_kafka", "test_kafka_rules_plaintext.yml"
)
Expand All @@ -54,7 +62,11 @@ def test_kafka_source_plaintext(kafka_certs, kafka_broker, kafka_producer) -> No


@pytest.mark.xfail(reason="https://github.com/ansible/event-driven-ansible/issues/234")
def test_kafka_source_with_headers(kafka_certs, kafka_broker, kafka_producer) -> None:
def test_kafka_source_with_headers(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
kafka_producer: Any,
) -> None:
ruleset = os.path.join(
TESTS_PATH, "event_source_kafka", "test_kafka_rules_headers.yml"
)
Expand All @@ -78,7 +90,11 @@ def test_kafka_source_with_headers(kafka_certs, kafka_broker, kafka_producer) ->


@pytest.mark.xfail(reason="https://github.com/ansible/event-driven-ansible/issues/234")
def test_kafka_source_ssl(kafka_certs, kafka_broker, kafka_producer) -> None:
def test_kafka_source_ssl(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
kafka_producer: Any,
) -> None:
ruleset = os.path.join(TESTS_PATH, "event_source_kafka", "test_kafka_rules_ssl.yml")

msgs = [
Expand All @@ -95,7 +111,11 @@ def test_kafka_source_ssl(kafka_certs, kafka_broker, kafka_producer) -> None:


@pytest.mark.xfail(reason="https://github.com/ansible/event-driven-ansible/issues/234")
def test_kafka_source_sasl_plaintext(kafka_certs, kafka_broker, kafka_producer) -> None:
def test_kafka_source_sasl_plaintext(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
kafka_producer: Any,
) -> None:
ruleset = os.path.join(
TESTS_PATH, "event_source_kafka", "test_kafka_rules_sasl_plaintext.yml"
)
Expand All @@ -116,7 +136,11 @@ def test_kafka_source_sasl_plaintext(kafka_certs, kafka_broker, kafka_producer)


@pytest.mark.xfail(reason="https://github.com/ansible/event-driven-ansible/issues/234")
def test_kafka_source_sasl_ssl(kafka_certs, kafka_broker, kafka_producer) -> None:
def test_kafka_source_sasl_ssl(
kafka_certs: subprocess.CompletedProcess[bytes],
kafka_broker: subprocess.CompletedProcess[bytes],
kafka_producer: Any,
) -> None:
ruleset = os.path.join(
TESTS_PATH, "event_source_kafka", "test_kafka_rules_sasl_ssl.yml"
)
Expand Down
15 changes: 10 additions & 5 deletions tests/integration/event_source_url_check/test_url_check_source.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import http.server
import os
import threading
from typing import Any, Generator
from typing import Any, Callable, Generator

import pytest

Expand All @@ -11,11 +11,11 @@


class HttpHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs) -> None:
def __init__(self, *args: Any, **kwargs: Any) -> None:
base_dir = os.path.join(TESTS_PATH, EVENT_SOURCE_DIR, "webserver_files")
super().__init__(*args, **kwargs, directory=base_dir)

def log_message(self, format, *args) -> None:
def log_message(self, format: str, *args: Any) -> None:
# do not log http.server messages
pass

Expand All @@ -40,7 +40,10 @@ def init_webserver() -> Generator[Any, Any, Any]:
],
)
def test_url_check_source_sanity(
init_webserver, subprocess_teardown, endpoint, expected_resp_data
init_webserver: None,
subprocess_teardown: Callable,
endpoint: str,
expected_resp_data: str,
) -> None:
"""
Ensure the url check plugin queries the desired endpoint
Expand All @@ -56,14 +59,15 @@ def test_url_check_source_sanity(
runner = CLIRunner(rules=ruleset, envvars="URL_ENDPOINT").run_in_background()
subprocess_teardown(runner)

assert runner.stdout is not None
while line := runner.stdout.readline().decode():
if "msg" in line:
assert f'"msg": "{expected_resp_data}"' in line
break


@pytest.mark.timeout(timeout=DEFAULT_TEST_TIMEOUT, method="signal")
def test_url_check_source_error_handling(subprocess_teardown) -> None:
def test_url_check_source_error_handling(subprocess_teardown: Callable) -> None:
"""
Ensure the url check source plugin responds correctly
when the desired HTTP server is unreachable
Expand All @@ -76,6 +80,7 @@ def test_url_check_source_error_handling(subprocess_teardown) -> None:
runner = CLIRunner(rules=ruleset).run_in_background()
subprocess_teardown(runner)

assert runner.stdout is not None
while line := runner.stdout.readline().decode():
if "msg" in line:
assert "Endpoint down" in line
Expand Down
15 changes: 9 additions & 6 deletions tests/integration/event_source_webhook/test_webhook_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import os
import subprocess
import time
from typing import Callable

import pytest
import requests

from ..utils import TESTS_PATH, CLIRunner


def wait_for_events(proc: subprocess.Popen, timeout: float = 15.0):
def wait_for_events(proc: subprocess.Popen, timeout: float = 15.0) -> None:
"""
Wait for events to be processed by ansible-rulebook, or timeout.
Requires the process to be running in debug mode.
Expand All @@ -32,7 +33,7 @@ def wait_for_events(proc: subprocess.Popen, timeout: float = 15.0):
pytest.param(5001, id="custom_port"),
],
)
def test_webhook_source_sanity(subprocess_teardown, port: int) -> None:
def test_webhook_source_sanity(subprocess_teardown: Callable, port: int) -> None:
"""
Check the successful execution, response and shutdown
of the webhook source plugin.
Expand All @@ -59,7 +60,7 @@ def test_webhook_source_sanity(subprocess_teardown, port: int) -> None:

for msg in msgs:
headers = {"Authorization": "Bearer secret"}
requests.post(url, data=msg, headers=headers)
requests.post(url, data=msg, headers=headers, timeout=5.0)

try:
stdout, _unused_stderr = proc.communicate(timeout=5)
Expand All @@ -72,7 +73,7 @@ def test_webhook_source_sanity(subprocess_teardown, port: int) -> None:
assert proc.returncode == 0


def test_webhook_source_with_busy_port(subprocess_teardown) -> None:
def test_webhook_source_with_busy_port(subprocess_teardown: Callable) -> None:
"""
Ensure the CLI responds correctly if the desired port is
already in use.
Expand All @@ -90,7 +91,7 @@ def test_webhook_source_with_busy_port(subprocess_teardown) -> None:
assert proc2.returncode == 1


def test_webhook_source_hmac_sanity(subprocess_teardown) -> None:
def test_webhook_source_hmac_sanity(subprocess_teardown: Callable) -> None:
"""
Check the successful execution, response and shutdown
of the webhook source plugin.
Expand Down Expand Up @@ -138,7 +139,9 @@ def test_webhook_source_hmac_sanity(subprocess_teardown) -> None:
assert proc.returncode == 0


def test_webhook_source_with_unsupported_hmac_algo(subprocess_teardown) -> None:
def test_webhook_source_with_unsupported_hmac_algo(
subprocess_teardown: Callable,
) -> None:
"""
Ensure the CLI responds correctly if the desired HMAC algorithm is not supported.
"""
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _process_args(self) -> List[str]:

return args

def run(self):
def run(self) -> subprocess.CompletedProcess:
args = self._process_args()
print("Running command: ", " ".join(args))
return subprocess.run(
Expand All @@ -66,7 +66,7 @@ def run(self):
env=self.env,
)

def run_in_background(self):
def run_in_background(self) -> subprocess.Popen:
args = self._process_args()
print("Running command: ", " ".join(args))
return subprocess.Popen(
Expand Down
42 changes: 22 additions & 20 deletions tests/unit/event_filter/test_insert_hosts_to_meta.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

import pytest

from extensions.eda.plugins.event_filter.insert_hosts_to_meta import PathNotExistError
Expand Down Expand Up @@ -39,34 +41,34 @@


@pytest.mark.parametrize("data, args, expected_hosts", EVENT_DATA_1)
def test_find_hosts(data, args, expected_hosts) -> None:
def test_find_hosts(data: dict, args: dict, expected_hosts: list) -> None:
data = hosts_main(data, **args)
if expected_hosts:
assert data["meta"]["hosts"] == expected_hosts
else:
assert "hosts" not in data["meta"]


EVENT_DATA_2 = [
(
{"app": {"target": 5000}},
{"host_path": "app.target"},
),
(
{"app": {"target": ("host1", 5000)}},
{"host_path": "app.target"},
),
(
{"app": {"target": {"foo": "bar"}}},
{"host_path": "app.target"},
),
]


@pytest.mark.parametrize("data, args", EVENT_DATA_2)
def test_fail_find_hosts(data, args) -> None:
@pytest.mark.parametrize(
"data, args",
[
pytest.param(
{"app": {"target": 5000}},
{"host_path": "app.target"},
),
pytest.param(
{"app": {"target": ("host1", 5000)}},
{"host_path": "app.target"},
),
pytest.param(
{"app": {"target": {"foo": "bar"}}},
{"host_path": "app.target"},
),
],
)
def test_fail_find_hosts(data: dict[str, Any], args: dict[str, str]) -> None:
with pytest.raises(TypeError):
hosts_main(data, **args)
hosts_main(data, **args) # type: ignore


def test_host_path_not_exist() -> None:
Expand Down
Loading

0 comments on commit eb8db79

Please sign in to comment.