MERGE: resolve conflicts

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2025-11-10 10:11:34 +11:00
77 changed files with 1670 additions and 811 deletions

View File

@@ -7,7 +7,8 @@ import pytest
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import get_setting_value, timeNowTZ
from helper import get_setting_value
from utils.datetime_utils import timeNowDB
from api_server.api_server_start import app
@@ -41,9 +42,12 @@ def b64(sql: str) -> str:
# Device lifecycle via dbquery endpoints
# -----------------------------
def test_dbquery_create_device(client, api_token, test_mac):
now = timeNowDB()
sql = f"""
INSERT INTO Devices (devMac, devName, devVendor, devOwner, devFirstConnection, devLastConnection, devLastIP)
VALUES ('{test_mac}', 'UnitTestDevice', 'TestVendor', 'UnitTest', '{timeNowTZ()}', '{timeNowTZ()}', '192.168.100.22' )
VALUES ('{test_mac}', 'UnitTestDevice', 'TestVendor', 'UnitTest', '{now}', '{now}', '192.168.100.22' )
"""
resp = client.post("/dbquery/write", json={"rawSql": b64(sql)}, headers=auth_headers(api_token))
print(resp.json)

View File

@@ -10,7 +10,7 @@ import pytest
INSTALL_PATH = os.getenv("NETALERTX_APP", "/app")
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from api_server.api_server_start import app

View File

@@ -11,7 +11,7 @@ import pytest
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from api_server.api_server_start import app
@pytest.fixture(scope="session")

View File

@@ -11,7 +11,8 @@ from datetime import datetime, timedelta
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from utils.datetime_utils import timeNowTZ
from api_server.api_server_start import app
@pytest.fixture(scope="session")

View File

@@ -0,0 +1,170 @@
import sys
import pathlib
import sqlite3
import random
import string
import uuid
import pytest
from datetime import datetime, timedelta
INSTALL_PATH = "/app"
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import get_setting_value
from api_server.api_server_start import app
@pytest.fixture(scope="session")
def api_token():
return get_setting_value("API_TOKEN")
@pytest.fixture
def client():
with app.test_client() as client:
yield client
@pytest.fixture
def test_mac():
# Generate a unique MAC for each test run
return "AA:BB:CC:" + ":".join(f"{random.randint(0,255):02X}" for _ in range(3))
def auth_headers(token):
return {"Authorization": f"Bearer {token}"}
def test_graphql_debug_get(client):
"""GET /graphql should return the debug string"""
resp = client.get("/graphql")
assert resp.status_code == 200
assert resp.data.decode() == "NetAlertX GraphQL server running."
def test_graphql_post_unauthorized(client):
"""POST /graphql without token should return 401"""
query = {"query": "{ devices { devName devMac } }"}
resp = client.post("/graphql", json=query)
assert resp.status_code == 401
assert "Unauthorized access attempt" in resp.json.get("error", "")
# --- DEVICES TESTS ---
def test_graphql_post_devices(client, api_token):
"""POST /graphql with a valid token should return device data"""
query = {
"query": """
{
devices {
devices {
devGUID
devGroup
devIsRandomMac
devParentChildrenCount
}
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
body = resp.get_json()
# GraphQL spec: response always under "data"
assert "data" in body
data = body["data"]
assert "devices" in data
assert isinstance(data["devices"]["devices"], list)
assert isinstance(data["devices"]["count"], int)
# --- SETTINGS TESTS ---
def test_graphql_post_settings(client, api_token):
"""POST /graphql should return settings data"""
query = {
"query": """
{
settings {
settings { setKey setValue setGroup }
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
data = resp.json.get("data", {})
assert "settings" in data
assert isinstance(data["settings"]["settings"], list)
# --- LANGSTRINGS TESTS ---
def test_graphql_post_langstrings_specific(client, api_token):
"""Retrieve a specific langString in a given language"""
query = {
"query": """
{
langStrings(langCode: "en_us", langStringKey: "settings_other_scanners") {
langStrings { langCode langStringKey langStringText }
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
data = resp.json.get("data", {}).get("langStrings", {})
assert data["count"] >= 1
for entry in data["langStrings"]:
assert entry["langCode"] == "en_us"
assert entry["langStringKey"] == "settings_other_scanners"
assert isinstance(entry["langStringText"], str)
def test_graphql_post_langstrings_fallback(client, api_token):
"""Fallback to en_us if requested language string is empty"""
query = {
"query": """
{
langStrings(langCode: "de_de", langStringKey: "settings_other_scanners") {
langStrings { langCode langStringKey langStringText }
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
data = resp.json.get("data", {}).get("langStrings", {})
assert data["count"] >= 1
# Ensure fallback occurred if de_de text is empty
for entry in data["langStrings"]:
assert entry["langStringText"] != ""
def test_graphql_post_langstrings_all_languages(client, api_token):
"""Retrieve all languages for a given key"""
query = {
"query": """
{
enStrings: langStrings(langCode: "en_us", langStringKey: "settings_other_scanners") {
langStrings { langCode langStringKey langStringText }
count
}
deStrings: langStrings(langCode: "de_de", langStringKey: "settings_other_scanners") {
langStrings { langCode langStringKey langStringText }
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
data = resp.json.get("data", {})
assert "enStrings" in data
assert "deStrings" in data
# At least one string in each language
assert data["enStrings"]["count"] >= 1
assert data["deStrings"]["count"] >= 1
# Ensure langCode matches
assert all(e["langCode"] == "en_us" for e in data["enStrings"]["langStrings"])
assert all(e["langCode"] == "de_de" for e in data["deStrings"]["langStrings"])

View File

@@ -10,7 +10,7 @@ import pytest
INSTALL_PATH = os.getenv("NETALERTX_APP", "/app")
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from api_server.api_server_start import app

View File

@@ -0,0 +1,61 @@
import sys
import random
import pytest
INSTALL_PATH = "/app"
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import get_setting_value
from api_server.api_server_start import app
# ----------------------------
# Fixtures
# ----------------------------
@pytest.fixture(scope="session")
def api_token():
return get_setting_value("API_TOKEN")
@pytest.fixture
def client():
with app.test_client() as client:
yield client
def auth_headers(token):
return {"Authorization": f"Bearer {token}"}
# ----------------------------
# Logs Endpoint Tests
# ----------------------------
def test_clean_log(client, api_token):
resp = client.delete("/logs?file=app.log", headers=auth_headers(api_token))
assert resp.status_code == 200
assert resp.json.get("success") is True
def test_clean_log_not_allowed(client, api_token):
resp = client.delete("/logs?file=not_allowed.log", headers=auth_headers(api_token))
assert resp.status_code == 400
assert resp.json.get("success") is False
# ----------------------------
# Execution Queue Endpoint Tests
# ----------------------------
def test_add_to_execution_queue(client, api_token):
action_name = f"test_action_{random.randint(0,9999)}"
resp = client.post(
"/logs/add-to-execution-queue",
json={"action": action_name},
headers=auth_headers(api_token)
)
assert resp.status_code == 200
assert resp.json.get("success") is True
assert action_name in resp.json.get("message", "")
def test_add_to_execution_queue_missing_action(client, api_token):
resp = client.post(
"/logs/add-to-execution-queue",
json={},
headers=auth_headers(api_token)
)
assert resp.status_code == 400
assert resp.json.get("success") is False
assert "Missing required 'action'" in resp.json.get("error", "")

View File

@@ -11,7 +11,7 @@ import pytest
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from api_server.api_server_start import app
@pytest.fixture(scope="session")

View File

@@ -11,7 +11,8 @@ from datetime import datetime, timedelta
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from utils.datetime_utils import timeNowTZ, timeNowDB
from api_server.api_server_start import app
@pytest.fixture(scope="session")
@@ -49,7 +50,7 @@ def test_create_session(client, api_token, test_mac):
payload = {
"mac": test_mac,
"ip": "192.168.1.100",
"start_time": timeNowTZ(),
"start_time": timeNowDB(),
"event_type_conn": "Connected",
"event_type_disc": "Disconnected"
}
@@ -64,7 +65,7 @@ def test_list_sessions(client, api_token, test_mac):
payload = {
"mac": test_mac,
"ip": "192.168.1.100",
"start_time": timeNowTZ()
"start_time": timeNowDB()
}
client.post("/sessions/create", json=payload, headers=auth_headers(api_token))
@@ -81,7 +82,7 @@ def test_device_sessions_by_period(client, api_token, test_mac):
payload = {
"mac": test_mac,
"ip": "192.168.1.200",
"start_time": timeNowTZ()
"start_time": timeNowDB()
}
resp_create = client.post("/sessions/create", json=payload, headers=auth_headers(api_token))
assert resp_create.status_code == 200
@@ -116,7 +117,7 @@ def test_device_session_events(client, api_token, test_mac):
payload = {
"mac": test_mac,
"ip": "192.168.1.250",
"start_time": timeNowTZ()
"start_time": timeNowDB()
}
resp_create = client.post(
"/sessions/create",
@@ -164,7 +165,7 @@ def test_delete_session(client, api_token, test_mac):
payload = {
"mac": test_mac,
"ip": "192.168.1.100",
"start_time": timeNowTZ()
"start_time": timeNowDB()
}
client.post("/sessions/create", json=payload, headers=auth_headers(api_token))

View File

@@ -11,7 +11,7 @@ from datetime import datetime, timedelta
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from helper import timeNowTZ, get_setting_value
from helper import get_setting_value
from api_server.api_server_start import app
@pytest.fixture(scope="session")

View File