mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 02:16:21 +00:00
Add installation date filtering to news display logic
Co-authored-by: MischaPanch <35432522+MischaPanch@users.noreply.github.com>
This commit is contained in:
1 parent
8515abec66
commit
61891370e4
2 files changed
+188
No files matched your search
@@ -2,6 +2,7 @@ import os
|
||||
import socket
|
||||
import threading
|
||||
from collections.abc import Callable
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Self
|
||||
|
||||
@@ -142,6 +143,31 @@ class SerenaDashboardAPI:
|
||||
def memory_log_handler(self) -> MemoryLogHandler:
|
||||
return self._memory_log_handler
|
||||
|
||||
@staticmethod
|
||||
def _get_installation_date_id() -> int:
|
||||
"""
|
||||
Get the installation date ID (YYYYMMDD format) based on the creation time
|
||||
of the SERENA_HOME directory.
|
||||
|
||||
:return: Installation date as an integer in YYYYMMDD format
|
||||
"""
|
||||
serena_home = SerenaPaths().serena_user_home_dir
|
||||
|
||||
# If SERENA_HOME doesn't exist yet, return today's date
|
||||
if not os.path.exists(serena_home):
|
||||
today = datetime.now()
|
||||
return int(today.strftime("%Y%m%d"))
|
||||
|
||||
# Get the creation/modification time of the SERENA_HOME directory
|
||||
stat_info = os.stat(serena_home)
|
||||
# Use st_ctime on Unix-like systems (change time, closest to creation time)
|
||||
# or st_mtime if ctime is not reliable
|
||||
creation_timestamp = stat_info.st_ctime
|
||||
creation_date = datetime.fromtimestamp(creation_timestamp)
|
||||
|
||||
# Return as YYYYMMDD integer
|
||||
return int(creation_date.strftime("%Y%m%d"))
|
||||
|
||||
def _setup_routes(self) -> None:
|
||||
# Static files
|
||||
@self._app.route("/dashboard/<path:filename>")
|
||||
@@ -324,6 +350,12 @@ class SerenaDashboardAPI:
|
||||
def _get_unread_news_ids() -> list[int]:
|
||||
all_news_files = (Path(SERENA_DASHBOARD_DIR) / "news").glob("*.html")
|
||||
all_news_ids = [int(f.stem) for f in all_news_files]
|
||||
|
||||
# Filter news items by installation date
|
||||
installation_date_id = self._get_installation_date_id()
|
||||
# Only include news items published on or after the installation date
|
||||
all_news_ids = [news_id for news_id in all_news_ids if news_id >= installation_date_id]
|
||||
|
||||
news_snippet_id_file = SerenaPaths().news_snippet_id_file
|
||||
if not os.path.exists(news_snippet_id_file):
|
||||
return all_news_ids
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
"""
|
||||
Tests for the dashboard API, specifically the news display logic.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from serena.dashboard import SerenaDashboardAPI
|
||||
|
||||
|
||||
class TestNewsDisplayLogic:
|
||||
"""Test the news display logic with installation date filtering."""
|
||||
|
||||
def test_get_installation_date_id_existing_dir(self):
|
||||
"""Test getting installation date from an existing directory."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Get the installation date ID
|
||||
with patch("serena.dashboard.SerenaPaths") as mock_paths:
|
||||
mock_paths_instance = MagicMock()
|
||||
mock_paths_instance.serena_user_home_dir = temp_dir
|
||||
mock_paths.return_value = mock_paths_instance
|
||||
|
||||
result = SerenaDashboardAPI._get_installation_date_id()
|
||||
|
||||
# Should return a valid YYYYMMDD format integer
|
||||
assert isinstance(result, int)
|
||||
assert 20000101 <= result <= 99991231 # Valid date range
|
||||
|
||||
# Should match today's or recent date (since we just created the directory)
|
||||
result_str = str(result)
|
||||
assert len(result_str) == 8
|
||||
year = int(result_str[0:4])
|
||||
month = int(result_str[4:6])
|
||||
day = int(result_str[6:8])
|
||||
assert 2020 <= year <= 2030 # Reasonable year range
|
||||
assert 1 <= month <= 12
|
||||
assert 1 <= day <= 31
|
||||
|
||||
def test_get_installation_date_id_nonexistent_dir(self):
|
||||
"""Test getting installation date when directory doesn't exist yet."""
|
||||
with patch("serena.dashboard.SerenaPaths") as mock_paths:
|
||||
mock_paths_instance = MagicMock()
|
||||
mock_paths_instance.serena_user_home_dir = "/nonexistent/path/that/does/not/exist"
|
||||
mock_paths.return_value = mock_paths_instance
|
||||
|
||||
result = SerenaDashboardAPI._get_installation_date_id()
|
||||
|
||||
# Should return today's date
|
||||
today = datetime.now()
|
||||
expected = int(today.strftime("%Y%m%d"))
|
||||
assert result == expected
|
||||
|
||||
def test_news_filtering_by_installation_date(self):
|
||||
"""Test that news items are filtered based on installation date."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Create a mock news directory with some news files
|
||||
news_dir = Path(temp_dir) / "news"
|
||||
news_dir.mkdir()
|
||||
|
||||
# Create news files with dates before and after a simulated installation date
|
||||
old_news_file = news_dir / "20250101.html"
|
||||
recent_news_file = news_dir / "20260201.html"
|
||||
future_news_file = news_dir / "20260301.html"
|
||||
|
||||
old_news_file.write_text("<div>Old news</div>")
|
||||
recent_news_file.write_text("<div>Recent news</div>")
|
||||
future_news_file.write_text("<div>Future news</div>")
|
||||
|
||||
# Mock the installation date to be 2026-02-01
|
||||
with patch.object(SerenaDashboardAPI, "_get_installation_date_id", return_value=20260201):
|
||||
# Create mocks for the API
|
||||
mock_memory_log_handler = MagicMock()
|
||||
mock_agent = MagicMock()
|
||||
mock_tool_usage_stats = MagicMock()
|
||||
|
||||
api = SerenaDashboardAPI(
|
||||
memory_log_handler=mock_memory_log_handler,
|
||||
tool_names=[],
|
||||
agent=mock_agent,
|
||||
tool_usage_stats=mock_tool_usage_stats,
|
||||
)
|
||||
|
||||
# Mock SERENA_DASHBOARD_DIR to point to our temp directory
|
||||
with patch("serena.dashboard.SERENA_DASHBOARD_DIR", temp_dir):
|
||||
# Mock SerenaPaths to return a non-existent news snippet file
|
||||
# so all news items are considered unread
|
||||
with patch("serena.dashboard.SerenaPaths") as mock_paths:
|
||||
mock_paths_instance = MagicMock()
|
||||
mock_paths_instance.news_snippet_id_file = os.path.join(temp_dir, "nonexistent.txt")
|
||||
mock_paths.return_value = mock_paths_instance
|
||||
|
||||
# Get the client
|
||||
client = api._app.test_client()
|
||||
response = client.get("/news_snippet_ids")
|
||||
data = response.get_json()
|
||||
|
||||
# Should only include news from 20260201 onwards (not 20250101)
|
||||
assert data["status"] == "success"
|
||||
news_ids = data["news_snippet_ids"]
|
||||
assert 20250101 not in news_ids # Old news filtered out
|
||||
assert 20260201 in news_ids # Recent news included
|
||||
assert 20260301 in news_ids # Future news included
|
||||
|
||||
def test_news_filtering_with_read_status(self):
|
||||
"""Test that news items respect both installation date and read status."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Create a mock news directory
|
||||
news_dir = Path(temp_dir) / "news"
|
||||
news_dir.mkdir()
|
||||
|
||||
# Create news files
|
||||
(news_dir / "20260201.html").write_text("<div>News 1</div>")
|
||||
(news_dir / "20260202.html").write_text("<div>News 2</div>")
|
||||
(news_dir / "20260203.html").write_text("<div>News 3</div>")
|
||||
|
||||
# Create a news snippet file marking 20260201 as read
|
||||
news_snippet_file = Path(temp_dir) / "last_read_news_snippet_id.txt"
|
||||
news_snippet_file.write_text("20260201")
|
||||
|
||||
# Mock the installation date to be 2026-02-01
|
||||
with patch.object(SerenaDashboardAPI, "_get_installation_date_id", return_value=20260201):
|
||||
# Create mocks for the API
|
||||
mock_memory_log_handler = MagicMock()
|
||||
mock_agent = MagicMock()
|
||||
mock_tool_usage_stats = MagicMock()
|
||||
|
||||
api = SerenaDashboardAPI(
|
||||
memory_log_handler=mock_memory_log_handler,
|
||||
tool_names=[],
|
||||
agent=mock_agent,
|
||||
tool_usage_stats=mock_tool_usage_stats,
|
||||
)
|
||||
|
||||
# Mock SERENA_DASHBOARD_DIR and SerenaPaths
|
||||
with patch("serena.dashboard.SERENA_DASHBOARD_DIR", temp_dir):
|
||||
with patch("serena.dashboard.SerenaPaths") as mock_paths:
|
||||
mock_paths_instance = MagicMock()
|
||||
mock_paths_instance.news_snippet_id_file = str(news_snippet_file)
|
||||
mock_paths.return_value = mock_paths_instance
|
||||
|
||||
# Get the client
|
||||
client = api._app.test_client()
|
||||
response = client.get("/news_snippet_ids")
|
||||
data = response.get_json()
|
||||
|
||||
# Should only include unread news after installation date
|
||||
assert data["status"] == "success"
|
||||
news_ids = data["news_snippet_ids"]
|
||||
assert 20260201 not in news_ids # Read
|
||||
assert 20260202 in news_ids # Unread and after installation
|
||||
assert 20260203 in news_ids # Unread and after installation
|
||||
Reference in new issue
Block a user