Files
ServerKit/backend/tests/test_app_observability_runtime.py

125 lines
4.4 KiB
Python

"""Runtime-aware application logs keep single-container and compose support."""
import os
from unittest.mock import patch
import pytest
from factories import headers_for, make_application, make_server, make_user
@pytest.fixture
def owner(app, db_session):
return make_user(db_session, role='admin', username='observability-owner')
def test_logs_prefer_a_live_recorded_container(client, db_session, owner, tmp_path):
"""A repository compose file does not override the deployed runtime."""
(tmp_path / 'docker-compose.yaml').write_text(
'services:\n db:\n image: postgres\n', encoding='utf-8')
application = make_application(
db_session,
name='standalone-api',
root_path=str(tmp_path),
compose_file=None,
container_id='runtime-container-id',
user_id=owner.id,
)
with patch('app.api.apps.DockerService.get_container',
return_value={'Id': 'runtime-container-id'}), \
patch('app.api.apps.DockerService.get_container_logs',
return_value={'success': True, 'logs': 'ready'}) as direct, \
patch('app.api.apps.LogService.get_docker_app_logs') as compose:
response = client.get(
f'/api/v1/apps/{application.id}/logs?lines=250',
headers=headers_for(owner),
)
assert response.status_code == 200
assert response.get_json()['logs'] == 'ready'
direct.assert_called_once_with(
'runtime-container-id', tail=250, timestamps=False)
compose.assert_not_called()
def test_logs_fall_back_to_compose_for_legacy_records(
client, db_session, owner, tmp_path):
application = make_application(
db_session,
name='legacy-compose',
root_path=str(tmp_path),
compose_file='compose.yaml',
container_id=None,
user_id=owner.id,
)
with patch('app.api.apps.LogService.get_docker_app_logs',
return_value={'success': True, 'logs': 'compose-ready'}) as compose:
response = client.get(
f'/api/v1/apps/{application.id}/logs?lines=75',
headers=headers_for(owner),
)
assert response.status_code == 200
assert response.get_json()['logs'] == 'compose-ready'
compose.assert_called_once_with(
'legacy-compose', str(tmp_path), 75, compose_file='compose.yaml')
def test_a_stale_recorded_container_keeps_the_compose_fallback(
client, db_session, owner, tmp_path):
application = make_application(
db_session,
name='recreated-compose',
root_path=str(tmp_path),
compose_file='compose.yaml',
container_id='removed-container-id',
user_id=owner.id,
)
with patch('app.api.apps.DockerService.get_container', return_value=None), \
patch('app.api.apps.DockerService.get_container_logs') as direct, \
patch('app.api.apps.LogService.get_docker_app_logs',
return_value={'success': True, 'logs': 'fallback-ready'}) as compose:
response = client.get(
f'/api/v1/apps/{application.id}/logs',
headers=headers_for(owner),
)
assert response.status_code == 200
assert response.get_json()['logs'] == 'fallback-ready'
direct.assert_not_called()
compose.assert_called_once()
def test_remote_logs_never_resolve_a_container_on_the_panel(
client, db_session, owner):
server = make_server(db_session, name='remote-runtime')
application = make_application(
db_session,
name='remote-api',
root_path='/srv/remote-api',
compose_file='compose.yaml',
container_id='runtime-container-id',
server_id=server.id,
user_id=owner.id,
)
with patch('app.api.apps.DockerService.get_container') as inspect, \
patch('app.api.apps.DockerService.get_container_logs') as direct, \
patch('app.api.apps.RemoteDockerService.compose_logs',
return_value={'success': True,
'data': {'logs': 'remote-ready'}}) as remote:
response = client.get(
f'/api/v1/apps/{application.id}/logs?lines=75',
headers=headers_for(owner),
)
assert response.status_code == 200
assert response.get_json()['logs'] == 'remote-ready'
inspect.assert_not_called()
direct.assert_not_called()
remote.assert_called_once_with(
server.id, os.path.join('/srv/remote-api', 'compose.yaml'), tail=75,
user_id=str(owner.id))