diff --git a/flake.nix b/flake.nix index ea4383f..76e570c 100644 --- a/flake.nix +++ b/flake.nix @@ -61,17 +61,17 @@ in '' ${ if builtins.elem "pytest" dev && !skipCheck - then "pytest src tests" + then "pytest tests" else "" } ${ if builtins.elem "mypy" dev && !skipCheck - then "mypy src tests" + then "mypy src" else "" } ${ if builtins.elem "pylint" dev && !skipCheck - then "pylint src tests" + then "pylint src" else "" } ''; diff --git a/pyproject.toml b/pyproject.toml index 9635067..8e161b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ where = ["src"] testdata = ["py.typed"] [tool.autopep8] -max_line_length = 150 +max_line_length = 175 [tool.pylint.'MESSAGES CONTROL'] disable = [ diff --git a/src/testdata/logger/logger.py b/src/testdata/logger/logger.py index 8c6b9a9..9e64f19 100644 --- a/src/testdata/logger/logger.py +++ b/src/testdata/logger/logger.py @@ -132,7 +132,7 @@ def generate_log_config(log_path: str | None = None) -> dict: 'class': logging.handlers.RotatingFileHandler, 'level': 'DEBUG', 'formatter': 'json', - 'filename': 'log.jsonl', + 'filename': log_path, 'maxBytes': 1024 * 1024 * 10, # 10 MiB 'backupCount': 3 }} if log_path is not None else {}), diff --git a/src/testdata/main.py b/src/testdata/main.py index daa378d..7861a20 100644 --- a/src/testdata/main.py +++ b/src/testdata/main.py @@ -1,12 +1,17 @@ import sys import argparse import asyncio +import shutil from .testdata import Testdata def parse_args(args: list[str]): - parser = argparse.ArgumentParser() - parser.add_argument('-c', '--config', type=argparse.FileType('r'), default='./config.json', help='Path to config file in JSON format.') + def formatter(prog): + return argparse.ArgumentDefaultsHelpFormatter(prog, max_help_position=shutil.get_terminal_size().columns) + + parser = argparse.ArgumentParser(formatter_class=formatter) + + parser.add_argument('-c', '--config', type=argparse.FileType('r'), default='./config.json', help='Path to config file in JSON format.', ) parser.add_argument('-l', '--listen', type=str, default='0.0.0.0', help='IP on which to listen.') parser.add_argument('-p', '--port', type=int, default='8080', help='Port on which to serve the webserver.') diff --git a/src/testdata/testdata.py b/src/testdata/testdata.py index 09c001d..8413d23 100644 --- a/src/testdata/testdata.py +++ b/src/testdata/testdata.py @@ -4,6 +4,8 @@ import asyncio import inspect import functools import random +import importlib.metadata +from datetime import datetime import uvicorn from typing_extensions import Annotated @@ -53,7 +55,7 @@ class Testdata: _config: Config _api: FastAPI - _state: dict[str, int] + _state: dict _logger: logger.Logger def __init__(self, config: Config): @@ -62,7 +64,10 @@ class Testdata: self._api = self._setup_api() # Store internal state - self._state = {'data-used': 0} + self._state = { + 'version': importlib.metadata.version('testdata'), # For future compatibility + 'data-used': {f'{(today := datetime.today()).year}-{today.month:02}': 0} # math each months data usage + } def _setup_api(self) -> FastAPI: api = FastAPI(docs_url='/', redoc_url=None) @@ -162,12 +167,15 @@ class Testdata: raise MaxSizePerRequestError # update internal state - if self._config.max_data < self._state['data-used'] + size: + current_date = f'{(today := datetime.today()).year}-{today.month:02}' + if current_date not in self._state['data-used']: + self._state['data-used'][current_date] = 0 + if self._config.max_data < self._state['data-used'][current_date] + size: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Service not available.' ) - self._state['data-used'] += size + self._state['data-used'][current_date] += size self._logger.debug('Successfully processed request.', extra=extra) return StreamingResponse( @@ -209,7 +217,7 @@ class Testdata: while True: file.seek(0) - json.dump(self._state, file) + json.dump(self._state, file, indent=2) file.truncate() await asyncio.sleep(self._config.database_update_interval) diff --git a/tests/test_testdata.py b/tests/test_testdata.py index 4ec3745..cb38bd8 100644 --- a/tests/test_testdata.py +++ b/tests/test_testdata.py @@ -102,15 +102,29 @@ def test_invalid_api_key(_server): 'database-update-interval': 0.1 })], indirect=['_server']) def test_check_database_update(_server): + import importlib.metadata + from datetime import datetime + database = _server with open(database, 'r', encoding='utf-8') as file: file.seek(0) - assert json.load(file) == {'data-used': 0} + today = datetime.today() + assert json.load(file) == { + 'version': importlib.metadata.version('testdata'), + 'data-used': { + f'{today.year}-{today.month:02}': 0 + } + } response = requests.get(f'{PROTOCOL}://{HOST}:{PORT}/zeros?api_key=one&size=100', timeout=TIMEOUT) assert response.status_code == 200 time.sleep(0.1) file.seek(0) - assert json.load(file) == {'data-used': 100} + assert json.load(file) == { + 'version': importlib.metadata.version('testdata'), + 'data-used': { + f'{today.year}-{today.month:02}': 100 + } + }