|
6 | 6 | import pytest_asyncio |
7 | 7 | from sqlalchemy.ext.asyncio import AsyncSession |
8 | 8 |
|
| 9 | +from dstack._internal.core.errors import ServerClientError |
9 | 10 | from dstack._internal.server.models import ProjectModel |
10 | 11 | from dstack._internal.server.schemas.logs import PollLogsRequest |
11 | 12 | from dstack._internal.server.schemas.runner import LogEvent as RunnerLogEvent |
@@ -590,6 +591,38 @@ def test_read_with_next_token(self, mock_es_client): |
590 | 591 | call_args = mock_es_client.search.call_args |
591 | 592 | assert call_args.kwargs["search_after"] == ["1696586513234", "doc1"] |
592 | 593 |
|
| 594 | + def test_read_with_malformed_next_token_raises_client_error(self, mock_es_client): |
| 595 | + """Test that malformed next_token raises ServerClientError (400) instead of IndexError (500).""" |
| 596 | + with patch("dstack._internal.server.services.logs.fluentbit.Elasticsearch") as mock: |
| 597 | + mock.return_value = mock_es_client |
| 598 | + reader = ElasticsearchReader( |
| 599 | + host="http://localhost:9200", |
| 600 | + index="dstack-logs", |
| 601 | + ) |
| 602 | + |
| 603 | + request = PollLogsRequest( |
| 604 | + run_name="test-run", |
| 605 | + job_submission_id=UUID("1b0e1b45-2f8c-4ab6-8010-a0d1a3e44e0e"), |
| 606 | + next_token="invalid_token_no_colon", |
| 607 | + limit=100, |
| 608 | + ) |
| 609 | + with pytest.raises(ServerClientError, match="Invalid next_token"): |
| 610 | + reader.read("test-stream", request) |
| 611 | + |
| 612 | + request.next_token = ":" |
| 613 | + with pytest.raises(ServerClientError, match="Invalid next_token"): |
| 614 | + reader.read("test-stream", request) |
| 615 | + |
| 616 | + request.next_token = ":doc1" |
| 617 | + with pytest.raises(ServerClientError, match="Invalid next_token"): |
| 618 | + reader.read("test-stream", request) |
| 619 | + |
| 620 | + request.next_token = "1696586513234:" |
| 621 | + with pytest.raises(ServerClientError, match="Invalid next_token"): |
| 622 | + reader.read("test-stream", request) |
| 623 | + |
| 624 | + mock_es_client.search.assert_not_called() |
| 625 | + |
593 | 626 | def test_close_closes_client(self, mock_es_client): |
594 | 627 | with patch("dstack._internal.server.services.logs.fluentbit.Elasticsearch") as mock: |
595 | 628 | mock.return_value = mock_es_client |
|
0 commit comments