mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-11-13 09:13:30 +01:00
feat: add filename linter and AI coding guidelines (#1477)
Add a configurable filename linter to enforce naming conventions and an AGENTS.md to guide AI coding agents in following project conventions. The guidelines steer code generation; the linter independently verifies filename compliance. Together, they improve consistency and reduce unnecessary files and review effort. Conflicting file names were renamed. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""EOS notifies ``ems.notify_url`` after a completed optimization."""
|
||||
|
||||
import json
|
||||
import threading
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from akkudoktoreos.core import ems as ems_module
|
||||
from akkudoktoreos.core.emsettings import EnergyManagementCommonSettings
|
||||
|
||||
|
||||
def _receiver():
|
||||
received: list[dict] = []
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self): # noqa: N802
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
received.append(
|
||||
{
|
||||
"path": self.path,
|
||||
"type": self.headers.get("Content-Type"),
|
||||
"body": json.loads(self.rfile.read(length)),
|
||||
}
|
||||
)
|
||||
self.send_response(204)
|
||||
self.end_headers()
|
||||
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
server = HTTPServer(("127.0.0.1", 0), Handler)
|
||||
threading.Thread(target=server.serve_forever, daemon=True).start()
|
||||
return server, received
|
||||
|
||||
|
||||
def test_completed_optimization_is_posted():
|
||||
server, received = _receiver()
|
||||
try:
|
||||
url = f"http://127.0.0.1:{server.server_port}/api/eos/solution-ready"
|
||||
event = {"event": "optimization_completed", "duration_s": 12.5}
|
||||
thread = ems_module.notify_optimization_completed(url, event)
|
||||
assert thread is not None
|
||||
thread.join(timeout=10)
|
||||
assert received == [
|
||||
{"path": "/api/eos/solution-ready", "type": "application/json", "body": event}
|
||||
]
|
||||
finally:
|
||||
server.shutdown()
|
||||
|
||||
|
||||
def test_no_url_no_notification():
|
||||
assert ems_module.notify_optimization_completed(None, {"event": "x"}) is None
|
||||
assert ems_module.notify_optimization_completed("", {"event": "x"}) is None
|
||||
|
||||
|
||||
def test_unreachable_receiver_is_logged_once(monkeypatch):
|
||||
warnings: list[str] = []
|
||||
monkeypatch.setattr(ems_module.logger, "warning", lambda *a, **k: warnings.append(a[0]))
|
||||
monkeypatch.setattr(ems_module, "_notify_failing", False)
|
||||
server, _ = _receiver()
|
||||
port = server.server_port
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
for _ in range(3):
|
||||
ems_module._post_notification(f"http://127.0.0.1:{port}/x", {"event": "x"})
|
||||
assert len(warnings) == 1
|
||||
|
||||
|
||||
def test_notify_url_setting():
|
||||
assert EnergyManagementCommonSettings().notify_url is None
|
||||
assert EnergyManagementCommonSettings(notify_url=" ").notify_url is None
|
||||
assert (
|
||||
EnergyManagementCommonSettings(notify_url=" http://127.0.0.1:8080/a ").notify_url
|
||||
== "http://127.0.0.1:8080/a"
|
||||
)
|
||||
with pytest.raises(ValidationError):
|
||||
EnergyManagementCommonSettings(notify_url="file:///etc/passwd")
|
||||
Reference in New Issue
Block a user