diff --git a/aw_server/api.py b/aw_server/api.py index bd7178e..a143c0c 100644 --- a/aw_server/api.py +++ b/aw_server/api.py @@ -17,6 +17,7 @@ from aw_core.log import get_log_file_path from aw_core.models import Event from aw_query import query2 +from aw_query.exceptions import QueryException from aw_transform import heartbeat_merge from .__about__ import __version__ @@ -342,8 +343,16 @@ def query2(self, name, query, timeperiods, cache): period = timeperiod.split("/")[ :2 ] # iso8601 timeperiods are separated by a slash - starttime = iso8601.parse_date(period[0]) - endtime = iso8601.parse_date(period[1]) + if len(period) != 2: + raise QueryException( + f"Invalid timeperiod '{timeperiod}': expected two ISO8601 " + "datetimes separated by a slash (start/end)" + ) + try: + starttime = iso8601.parse_date(period[0]) + endtime = iso8601.parse_date(period[1]) + except iso8601.ParseError as e: + raise QueryException(f"Invalid timeperiod '{timeperiod}': {e}") query = "".join(query) result.append(query2.query(name, query, starttime, endtime, self.db)) return result diff --git a/tests/test_server.py b/tests/test_server.py index 1c1c2ea..0c49e44 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -89,3 +89,43 @@ def get_events(): # TODO: Add benchmark for basic AFK-filtering query + + +def test_query_invalid_timeperiod(flask_client): + """Malformed timeperiods must yield 400 (client error), not 500. + + Regression test: a non-ISO8601 timeperiod previously raised an uncaught + iso8601.ParseError, surfacing as an Internal Server Error. + """ + r = flask_client.post( + "/api/0/query/", + json={"query": ["RETURN = 1;"], "timeperiods": ["not-a-valid-period"]}, + ) + assert r.status_code == 400 + assert "not-a-valid-period" in r.json["message"] + + +def test_query_timeperiod_missing_slash(flask_client): + """A timeperiod without a start/end slash separator must yield 400, not 500. + + Regression test: a single ISO8601 datetime (no slash) previously raised an + uncaught IndexError when indexing the split result. + """ + r = flask_client.post( + "/api/0/query/", + json={"query": ["RETURN = 1;"], "timeperiods": ["2024-01-01T00:00:00+00:00"]}, + ) + assert r.status_code == 400 + + +def test_query_valid_timeperiod(flask_client): + """A well-formed query with a valid timeperiod still succeeds.""" + r = flask_client.post( + "/api/0/query/", + json={ + "query": ["RETURN = 1;"], + "timeperiods": ["2024-01-01T00:00:00+00:00/2024-01-02T00:00:00+00:00"], + }, + ) + assert r.status_code == 200 + assert r.json == [1]