Skip to content

Commit 5855b61

Browse files
committed
feat: add validations
1 parent bd4fcfd commit 5855b61

6 files changed

Lines changed: 82 additions & 22 deletions

File tree

pyproject.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@ build-backend = "flit_core.buildapi"
44

55
[project]
66
authors = [{ name = "Erik Kalkoken", email = "kalkoken87@gmail.com" }]
7-
dynamic = ["version", "description"]
8-
license = "MIT"
9-
license-files = ["LICENSE"]
10-
name = "victorialogs-handler"
11-
readme = "README.md"
127
classifiers = [
138
"Environment :: Web Environment",
149
"Intended Audience :: Developers",
@@ -21,6 +16,12 @@ classifiers = [
2116
"Programming Language :: Python :: 3.13",
2217
"Topic :: System :: Logging",
2318
]
19+
dynamic = ["version", "description"]
20+
license = "MIT"
21+
license-files = ["LICENSE"]
22+
name = "victorialogs-handler"
23+
readme = "README.md"
24+
requires-python = ">=3.10"
2425

2526
[project.urls]
2627
Home = "https://github.com/ErikKalkoken/python-victorialogs-handler"

src/vlogs_handler/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,4 @@
33
from .handler import VictoriaLogsHandler # noqa: F401
44

55
__title__ = "Victoria Logs Handler"
6-
__version__ = "0.1.0dev3"
7-
8-
# TO-DOs
9-
# [ ] Add validations
6+
__version__ = "0.1.0dev4"

src/vlogs_handler/handler.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,27 @@ def __init__(
7272
url: str = "http://localhost:9428",
7373
):
7474
super().__init__()
75-
self._batch_size = batch_size
76-
self._queue = queue.Queue(-1)
77-
self._request_timeout = request_timeout
78-
self._url = url
75+
76+
if batch_size < 1:
77+
raise ValueError(f"batch size must be >= 1 {batch_size}")
78+
79+
if request_timeout <= 0:
80+
raise ValueError(f"request_timeout must be > 0: {request_timeout}")
81+
82+
if not request.is_url(url):
83+
raise ValueError(f"url is not valid: {url}")
84+
7985
name = __package__
8086
if not name:
81-
raise RuntimeError("Must be run as module")
87+
raise RuntimeError("Must run as module")
88+
8289
self.addFilter(_create_filter(name))
8390

91+
self._batch_size = int(batch_size)
92+
self._queue = queue.Queue(-1)
93+
self._request_timeout = float(request_timeout)
94+
self._url = url
95+
8496
# Start background worker
8597
self._worker_thread = threading.Thread(target=self._worker, daemon=True)
8698
self._worker_started = False
@@ -202,3 +214,4 @@ def _calc_stream_from_record(record: logging.LogRecord):
202214
else:
203215
stream = record.name
204216
return stream
217+
return stream

src/vlogs_handler/request.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22

33
import logging
44
import urllib.error
5+
import urllib.parse
56
import urllib.request
67
from typing import Optional
78

89
logger = logging.getLogger(__name__)
910

1011

12+
def is_url(url: str) -> bool:
13+
"""Report whether a string represents a valid URL."""
14+
try:
15+
result = urllib.parse.urlparse(url)
16+
return all([result.scheme, result.netloc])
17+
except ValueError:
18+
return False
19+
20+
1121
def post_ndjson(*, url: str, data: str, timeout: Optional[float] = None) -> bool:
1222
"""Send a POST request with the ndjson protocol
1323
and report whether it was successful.

tests/test_handler.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,30 @@
1010
MODULE_PATH = "vlogs_handler.handler"
1111

1212

13+
class TestVictoriaLogsHandler_Validations(unittest.TestCase):
14+
def test_should_validate_batch_size(self):
15+
with self.assertRaises(ValueError):
16+
VictoriaLogsHandler(batch_size=0)
17+
18+
with self.assertRaises(ValueError):
19+
VictoriaLogsHandler(batch_size=-1)
20+
21+
def test_should_should_validate_request_timeout(self):
22+
with self.assertRaises(ValueError):
23+
VictoriaLogsHandler(request_timeout=0)
24+
25+
with self.assertRaises(ValueError):
26+
VictoriaLogsHandler(request_timeout=-1)
27+
28+
def test_should_should_validate_url(self):
29+
with self.assertRaises(ValueError):
30+
VictoriaLogsHandler(url="123")
31+
32+
1333
@patch(MODULE_PATH + ".request.post_ndjson")
1434
class TestVictoriaLogsHandler_SingleLog(unittest.TestCase):
1535
def setUp(self):
16-
self.handler = VictoriaLogsHandler(url="http://localhost:30123")
36+
self.handler = VictoriaLogsHandler()
1737
self.logger = logging.getLogger("test_logger")
1838
self.logger.addHandler(self.handler)
1939
self.logger.setLevel(logging.INFO)
@@ -94,7 +114,7 @@ def test_should_do_nothing_when_trying_to_start_again(self, _):
94114
@patch(MODULE_PATH + ".request.post_ndjson")
95115
class TestVictoriaLogsHandler_MultipleLogs(unittest.TestCase):
96116
def setUp(self):
97-
self.handler = VictoriaLogsHandler(url="http://localhost:30123", batch_size=3)
117+
self.handler = VictoriaLogsHandler(batch_size=3)
98118
self.logger = logging.getLogger("test_logger")
99119
self.logger.addHandler(self.handler)
100120
self.logger.setLevel(logging.INFO)

tests/test_request.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from contextlib import contextmanager
44
from http.client import HTTPMessage
55
from io import BytesIO
6+
from typing import NamedTuple
67
from unittest.mock import MagicMock, patch
78

8-
from vlogs_handler.request import post_ndjson
9+
from vlogs_handler import request
910

1011
MODULE_PATH = "vlogs_handler.request"
1112

@@ -20,7 +21,7 @@ def make_http_error(status=404, message="Not Found", url="https://example.com"):
2021

2122
def make_urlopen_fake(exception=None):
2223
@contextmanager
23-
def urlopen_fake(*args, **kwargs):
24+
def urlopen_fake(req, timeout):
2425
if exception:
2526
raise exception
2627
yield MagicMock()
@@ -37,7 +38,7 @@ def test_should_submit_successfully(self):
3738
# when
3839
with patch(MODULE_PATH + ".urllib.request.urlopen") as m:
3940
m.side_effect = make_urlopen_fake()
40-
got = post_ndjson(url=url, data=data)
41+
got = request.post_ndjson(url=url, data=data)
4142

4243
# then
4344
self.assertTrue(got)
@@ -50,7 +51,7 @@ def test_should_handle_http_exception(self):
5051
# when
5152
with patch(MODULE_PATH + ".urllib.request.urlopen") as m:
5253
m.side_effect = make_urlopen_fake(exception=make_http_error())
53-
got = post_ndjson(url=url, data=data)
54+
got = request.post_ndjson(url=url, data=data)
5455

5556
# then
5657
self.assertFalse(got)
@@ -65,7 +66,7 @@ def test_should_handle_url_exception(self):
6566
m.side_effect = make_urlopen_fake(
6667
exception=urllib.error.URLError("Network is unreachable")
6768
)
68-
got = post_ndjson(url=url, data=data)
69+
got = request.post_ndjson(url=url, data=data)
6970

7071
# then
7172
self.assertFalse(got)
@@ -79,7 +80,25 @@ def test_should_handle_general_exception(self):
7980
# when
8081
with patch(MODULE_PATH + ".urllib.request.urlopen") as m:
8182
m.side_effect = make_urlopen_fake(exception=RuntimeError)
82-
got = post_ndjson(url=url, data=data, timeout=timeout)
83+
got = request.post_ndjson(url=url, data=data, timeout=timeout)
8384

8485
# then
8586
self.assertFalse(got)
87+
88+
89+
class TestIsURL(unittest.TestCase):
90+
def test_all(self):
91+
class Case(NamedTuple):
92+
url: str
93+
want: bool
94+
95+
cases = [
96+
Case("http://www.example.com", True),
97+
Case("http://localhost:9428", True),
98+
Case("http://0.0.0.0:9428", True),
99+
Case("www.example.com", False),
100+
]
101+
102+
for tc in cases:
103+
with self.subTest(url=tc.url):
104+
self.assertIs(request.is_url(tc.url), tc.want)

0 commit comments

Comments
 (0)