Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Emit Daemon logs for pytest test run #6671

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions src/aiida/tools/pytest_fixtures/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

from __future__ import annotations

import logging
import pathlib
import typing as t

import pytest

if t.TYPE_CHECKING:
from aiida.engine import Process, ProcessBuilder
from aiida.engine.daemon.client import DaemonClient
from aiida.orm import ProcessNode


Expand Down Expand Up @@ -47,7 +49,7 @@ def test(daemon_client):


@pytest.fixture
def started_daemon_client(daemon_client):
def started_daemon_client(daemon_client: 'DaemonClient'):
"""Ensure that the daemon is running for the test profile and return the associated client.

Usage::
Expand All @@ -60,11 +62,61 @@ def test(started_daemon_client):
daemon_client.start_daemon()
assert daemon_client.is_daemon_running

import threading
import time

from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer

logger = logging.getLogger('tests.daemon:started_daemon_client')

logger.debug(f'Daemon log file is located at: {daemon_client.daemon_log_file}')

# This flag will be used to stop the thread when the fixture is torn down
stop_thread = False

class LogFileEventHandler(FileSystemEventHandler):
def __init__(self, filepath):
self.filepath = filepath
# Keep track of how many bytes have been read so we print only new data
self._pos = 0

def on_modified(self, event):
if event.src_path == self.filepath:
# The file was modified, read from the last known position
with open(self.filepath, 'r') as f:
f.seek(self._pos)
new_output = f.read()
if new_output:
logger.debug(new_output)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should not use logger here since the content of the log file is in log format.

self._pos = f.tell()

def print_log_content(check_interval=0.1):
event_handler = LogFileEventHandler(daemon_client.daemon_log_file)
observer = Observer()
_ = observer.schedule(event_handler, str(pathlib.Path(daemon_client.daemon_log_file)), recursive=False)
observer.start()

try:
while not stop_thread:
time.sleep(check_interval)
finally:
observer.stop()
observer.join()

# Start a background thread to continuously print new log lines
t = threading.Thread(target=print_log_content, daemon=True)
t.start()

yield daemon_client

# After the test finishes, signal the thread to stop and join it
stop_thread = True
t.join(timeout=5)


@pytest.fixture
def stopped_daemon_client(daemon_client):
def stopped_daemon_client(daemon_client: 'DaemonClient'):
"""Ensure that the daemon is not running for the test profile and return the associated client.

Usage::
Expand Down
Loading