Files
wehub-resource-sync fed8b2eed7
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Backend release / release (push) Has been cancelled
Bandit Security Scan / bandit_scan (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / manifest (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / manifest (push) Has been cancelled
Python linting / ruff (push) Has been cancelled
Run python tests with pytest / Run tests and count coverage (3.12) (push) Has been cancelled
React Widget Build / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

378 lines
12 KiB
Python

"""Tests for application/seed/seeder.py."""
from contextlib import contextmanager
from unittest.mock import MagicMock, patch
import pytest
from application.seed.seeder import DatabaseSeeder, SYSTEM_USER_ID
@contextmanager
def _patch_db(conn):
@contextmanager
def _yield():
yield conn
with patch(
"application.seed.seeder.db_session", _yield
), patch(
"application.seed.seeder.db_readonly", _yield
):
yield
class TestDatabaseSeederBasics:
def test_constructor_takes_optional_legacy_db(self):
s1 = DatabaseSeeder()
s2 = DatabaseSeeder(db=MagicMock())
assert s1.system_user_id == SYSTEM_USER_ID
assert s2.system_user_id == SYSTEM_USER_ID
def test_initialize_from_env_returns_instance(self):
s = DatabaseSeeder.initialize_from_env()
assert isinstance(s, DatabaseSeeder)
class TestCoerceUuidFk:
def test_none_returns_none(self):
assert DatabaseSeeder._coerce_uuid_fk(None) is None
def test_empty_returns_none(self):
assert DatabaseSeeder._coerce_uuid_fk("") is None
def test_default_returns_none(self):
assert DatabaseSeeder._coerce_uuid_fk("default") is None
def test_uuid_string_returned_as_is(self):
assert (
DatabaseSeeder._coerce_uuid_fk(
"00000000-0000-0000-0000-000000000001"
)
== "00000000-0000-0000-0000-000000000001"
)
class TestProcessConfig:
def test_passes_through_plain_values(self):
seeder = DatabaseSeeder()
result = seeder._process_config({"x": 1, "y": "foo"})
assert result == {"x": 1, "y": "foo"}
def test_resolves_env_var_placeholder(self, monkeypatch):
monkeypatch.setenv("SEED_TEST_VAR", "the-value")
seeder = DatabaseSeeder()
result = seeder._process_config({"key": "${SEED_TEST_VAR}"})
assert result == {"key": "the-value"}
def test_missing_env_var_resolves_to_empty(self, monkeypatch):
monkeypatch.delenv("NOT_SET_VAR", raising=False)
seeder = DatabaseSeeder()
result = seeder._process_config({"key": "${NOT_SET_VAR}"})
assert result == {"key": ""}
def test_string_not_placeholder_passes_through(self):
seeder = DatabaseSeeder()
assert seeder._process_config({"k": "plain-string"}) == {"k": "plain-string"}
class TestIsAlreadySeeded:
def test_false_when_no_system_agents(self, pg_conn):
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
assert seeder._is_already_seeded() is False
def test_true_when_system_agents_exist(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
AgentsRepository(pg_conn).create(
SYSTEM_USER_ID, "TemplateAgent", "template",
)
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
assert seeder._is_already_seeded() is True
class TestFindSystemAgentByName:
def test_returns_none_when_not_found(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
got = DatabaseSeeder._find_system_agent_by_name(
AgentsRepository(pg_conn), "missing"
)
assert got is None
def test_returns_agent_when_name_matches(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
repo = AgentsRepository(pg_conn)
repo.create(SYSTEM_USER_ID, "Match", "template")
got = DatabaseSeeder._find_system_agent_by_name(repo, "Match")
assert got is not None
assert got["name"] == "Match"
class TestFindSystemSourceByRemoteUrl:
def test_returns_none_when_repo_lacks_list(self):
class FakeRepo:
pass
assert (
DatabaseSeeder._find_system_source_by_remote_url(FakeRepo(), "x")
is None
)
def test_returns_none_when_no_match(self, pg_conn):
from application.storage.db.repositories.sources import SourcesRepository
got = DatabaseSeeder._find_system_source_by_remote_url(
SourcesRepository(pg_conn), "https://no-match"
)
assert got is None
def test_matches_dict_remote_data_url(self, pg_conn):
from application.storage.db.repositories.sources import SourcesRepository
repo = SourcesRepository(pg_conn)
repo.create(
"hello-src",
user_id=SYSTEM_USER_ID,
remote_data={"url": "https://example.com/data", "loader": "url"},
)
got = DatabaseSeeder._find_system_source_by_remote_url(
repo, "https://example.com/data"
)
assert got is not None
class TestHandlePrompt:
def test_returns_none_when_no_prompt_field(self, pg_conn):
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
assert seeder._handle_prompt({"name": "agent"}) is None
def test_returns_none_when_empty_content(self, pg_conn):
seeder = DatabaseSeeder()
agent_cfg = {
"name": "a",
"prompt": {"name": "p", "content": ""},
}
with _patch_db(pg_conn):
assert seeder._handle_prompt(agent_cfg) is None
def test_creates_prompt_and_returns_id(self, pg_conn):
seeder = DatabaseSeeder()
agent_cfg = {
"name": "a",
"prompt": {"name": "test-prompt", "content": "some content"},
}
with _patch_db(pg_conn):
pid = seeder._handle_prompt(agent_cfg)
assert pid is not None
from application.storage.db.repositories.prompts import PromptsRepository
prompts = PromptsRepository(pg_conn).list_for_user(SYSTEM_USER_ID)
assert any(p["name"] == "test-prompt" for p in prompts)
def test_handles_exception_returns_none(self, pg_conn):
seeder = DatabaseSeeder()
@contextmanager
def _broken():
raise RuntimeError("boom")
yield
with patch(
"application.seed.seeder.db_session", _broken
):
result = seeder._handle_prompt(
{
"name": "a",
"prompt": {"name": "p", "content": "c"},
}
)
assert result is None
class TestHandleTools:
def test_returns_empty_when_no_tools(self, pg_conn):
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
assert seeder._handle_tools({"name": "a"}) == []
class TestHandleSource:
def test_returns_none_when_no_source(self, pg_conn):
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
assert seeder._handle_source({"name": "a"}) is None
def test_returns_existing_source_id(self, pg_conn):
seeder = DatabaseSeeder()
from application.storage.db.repositories.sources import SourcesRepository
src = SourcesRepository(pg_conn).create(
"existing",
user_id=SYSTEM_USER_ID,
remote_data={"url": "https://example.com/x", "loader": "url"},
)
agent_cfg = {
"name": "a",
"source": {"url": "https://example.com/x", "name": "src"},
}
with _patch_db(pg_conn):
got = seeder._handle_source(agent_cfg)
assert got == src["id"]
def test_ingest_task_failure_returns_false(self, pg_conn):
seeder = DatabaseSeeder()
fake_task = MagicMock()
fake_task.get.side_effect = RuntimeError("ingestion failed")
with _patch_db(pg_conn), patch(
"application.seed.seeder.ingest_remote.delay",
return_value=fake_task,
):
got = seeder._handle_source(
{
"name": "a",
"source": {
"url": "https://example.com/new",
"name": "s",
},
}
)
assert got is False
def test_successful_ingest_returns_id(self, pg_conn):
seeder = DatabaseSeeder()
fake_task = MagicMock()
fake_task.get.return_value = {"id": "abc-id"}
fake_task.successful.return_value = True
with _patch_db(pg_conn), patch(
"application.seed.seeder.ingest_remote.delay",
return_value=fake_task,
):
got = seeder._handle_source(
{
"name": "a",
"source": {
"url": "https://example.com/brand-new",
"name": "s",
},
}
)
assert got == "abc-id"
def test_task_result_missing_id_returns_false(self, pg_conn):
seeder = DatabaseSeeder()
fake_task = MagicMock()
fake_task.get.return_value = "just-a-string"
fake_task.successful.return_value = True
with _patch_db(pg_conn), patch(
"application.seed.seeder.ingest_remote.delay",
return_value=fake_task,
):
got = seeder._handle_source(
{
"name": "a",
"source": {
"url": "https://example.com/noid",
"name": "s",
},
}
)
assert got is False
class TestUpsertAgent:
def test_creates_new_agent(self, pg_conn):
seeder = DatabaseSeeder()
agent_cfg = {
"name": "TemplateA",
"description": "desc",
"agent_type": "classic",
"chunks": "2",
"retriever": "classic",
}
with _patch_db(pg_conn):
seeder._upsert_agent(agent_cfg, None, [], None)
from application.storage.db.repositories.agents import AgentsRepository
rows = AgentsRepository(pg_conn).list_for_user(SYSTEM_USER_ID)
assert any(r["name"] == "TemplateA" for r in rows)
def test_updates_existing_agent(self, pg_conn):
seeder = DatabaseSeeder()
agent_cfg = {
"name": "TemplateB",
"description": "orig",
"agent_type": "classic",
}
with _patch_db(pg_conn):
seeder._upsert_agent(agent_cfg, None, [], None)
agent_cfg["description"] = "updated"
seeder._upsert_agent(agent_cfg, None, [], None)
from application.storage.db.repositories.agents import AgentsRepository
rows = AgentsRepository(pg_conn).list_for_user(SYSTEM_USER_ID)
matching = [r for r in rows if r["name"] == "TemplateB"]
assert len(matching) == 1
assert matching[0]["description"] == "updated"
class TestSeedFromConfig:
def test_no_agents_in_config_warns_and_returns(self, pg_conn):
seeder = DatabaseSeeder()
seeder._seed_from_config({})
# Should not raise; just log a warning
def test_processes_agents(self, pg_conn):
seeder = DatabaseSeeder()
cfg = {
"agents": [
{
"name": "FromConfigA",
"description": "d",
"agent_type": "classic",
},
{
"name": "FromConfigB",
"description": "d2",
"agent_type": "classic",
},
]
}
with _patch_db(pg_conn):
seeder._seed_from_config(cfg)
from application.storage.db.repositories.agents import AgentsRepository
rows = AgentsRepository(pg_conn).list_for_user(SYSTEM_USER_ID)
names = [r["name"] for r in rows]
assert "FromConfigA" in names and "FromConfigB" in names
class TestSeedInitialData:
def test_skips_when_already_seeded(self, pg_conn):
from application.storage.db.repositories.agents import AgentsRepository
# Seed one template so _is_already_seeded returns True
AgentsRepository(pg_conn).create(SYSTEM_USER_ID, "existing", "template")
seeder = DatabaseSeeder()
with _patch_db(pg_conn):
# Should not raise and not do any work
seeder.seed_initial_data(force=False)
def test_raises_on_bad_config_path(self, pg_conn):
seeder = DatabaseSeeder()
with _patch_db(pg_conn), pytest.raises(Exception):
seeder.seed_initial_data(
config_path="/nonexistent-seeder-path.yaml", force=True,
)