Files
DECNET/tests/db/mysql/test_mysql_histogram_sql.py
anti f2b3393669 chore: relicense to AGPL-3.0-or-later and add SPDX headers
Replaces LICENSE (GPLv3 -> AGPLv3) and prepends
`SPDX-License-Identifier: AGPL-3.0-or-later` to every source file
across decnet/, decnet_web/, tests/, scripts/, and tools/.

Rationale: closes the GPLv3 ASP loophole so any party operating a
modified DECNET as a network service must offer their modified
source. Personal copyright (Samuel Paschuan) + inbound=outbound
contributions make a future unilateral relicense infeasible.

- LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt)
- COPYRIGHT: project copyright notice
- tools/add_spdx_headers.py: idempotent header injector
  (shebang- and PEP 263-aware)

Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh).
No behavior change; comments only.
2026-05-22 21:04:16 -04:00

72 lines
2.7 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Inspection-level tests for the MySQL-dialect SQL emitted by MySQLRepository.
We compile the SQLAlchemy statements against the MySQL dialect and assert on
the string form — no live MySQL server is required.
"""
import pytest
from sqlalchemy import func, select, literal_column
from sqlalchemy.dialects import mysql
from sqlmodel.sql.expression import SelectOfScalar
from decnet.web.db.models import Log
def _compile(stmt) -> str:
"""Compile a statement to MySQL-dialect SQL with literal values inlined."""
return str(stmt.compile(
dialect=mysql.dialect(),
compile_kwargs={"literal_binds": True},
))
def test_mysql_histogram_uses_from_unixtime_bucket():
"""The MySQL dialect must bucket with UNIX_TIMESTAMP DIV N * N wrapped in FROM_UNIXTIME."""
bucket_seconds = 900 # 15 min
bucket_expr = literal_column(
f"FROM_UNIXTIME((UNIX_TIMESTAMP(timestamp) DIV {bucket_seconds}) * {bucket_seconds})"
).label("bucket_time")
stmt: SelectOfScalar = select(bucket_expr, func.count().label("count")).select_from(Log)
sql = _compile(stmt)
assert "FROM_UNIXTIME" in sql
assert "UNIX_TIMESTAMP" in sql
assert "DIV 900" in sql
# Sanity: SQLite-only strftime must NOT appear in the MySQL-dialect output.
assert "strftime" not in sql
assert "unixepoch" not in sql
def test_mysql_json_unquote_predicate_shape():
"""MySQL JSON filter uses JSON_UNQUOTE(JSON_EXTRACT(...))."""
from decnet.web.db.mysql.repository import MySQLRepository
# Build a dummy instance without touching the engine. We only need _json_field_equals,
# which is a pure function of the key.
repo = MySQLRepository.__new__(MySQLRepository) # bypass __init__ / no DB connection
predicate = repo._json_field_equals("username")
# text() objects carry their literal SQL in .text
assert "JSON_UNQUOTE" in predicate.text
assert "JSON_EXTRACT(fields, '$.username')" in predicate.text
assert ":val" in predicate.text
@pytest.mark.parametrize("key", ["user", "port", "sess_id"])
def test_mysql_json_predicate_safe_for_reasonable_keys(key):
"""Keys matching [A-Za-z0-9_]+ are inserted verbatim; verify no SQL breakage."""
from decnet.web.db.mysql.repository import MySQLRepository
repo = MySQLRepository.__new__(MySQLRepository)
pred = repo._json_field_equals(key)
assert f"'$.{key}'" in pred.text
def test_sqlite_histogram_still_uses_strftime():
"""Regression guard — SQLite implementation must keep its strftime-based bucket."""
from decnet.web.db.sqlite.repository import SQLiteRepository
import inspect
src = inspect.getsource(SQLiteRepository.get_log_histogram)
assert "strftime" in src
assert "unixepoch" in src