From 2afbc32a4872d086751f8d308b69697118a69c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20St=C3=B6ckli?= Date: Tue, 21 Oct 2025 14:59:57 +0000 Subject: [PATCH 1/2] initial pytest setup with initial TestYamlParser tests --- pytest.ini | 6 +++ requirements-test.txt | 1 + tests/README.md | 33 ++++++++++++++++ tests/__init__.py | 1 + tests/test_yaml_parser.py | 83 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 pytest.ini create mode 100644 requirements-test.txt create mode 100644 tests/README.md create mode 100644 tests/__init__.py create mode 100644 tests/test_yaml_parser.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..3a0c46d --- /dev/null +++ b/pytest.ini @@ -0,0 +1,6 @@ +[tool:pytest] +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = -v --tb=short \ No newline at end of file diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000..ca2a549 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1 @@ +pytest==8.4.2 \ No newline at end of file diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..6980e16 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,33 @@ +# Python Tests + +based on pytest. + +## Running Tests + +Make sure to install test dependencies: `pip install -r requirements-test.txt`. + +### All Tests + +```bash +pytest +``` + + +### Specific Test File +```bash +pytest tests/test_yaml_parser.py -v +``` + +### Specific Test Class +```bash +pytest tests/test_yaml_parser.py::TestYamlParser -v +``` + +### Specific Test Function +```bash +pytest tests/test_yaml_parser.py::TestYamlParser::test_yaml_parser_basic_functionality -v +``` + +## Test Configuration + +See `pytest.ini` in the root directory. \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..83922b0 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# this file makes the tests directory a Python package \ No newline at end of file diff --git a/tests/test_yaml_parser.py b/tests/test_yaml_parser.py new file mode 100644 index 0000000..8111d1c --- /dev/null +++ b/tests/test_yaml_parser.py @@ -0,0 +1,83 @@ +""" +Basic tests for YAML parsing functionality in the taskflow agent. + +Simple parsing + parsing of example taskflows. +""" + +import pytest +import tempfile +from pathlib import Path +import yaml +from yaml_parser import YamlParser + + +class TestYamlParser: + """Test suite for YamlParser class.""" + + def test_yaml_parser_basic_functionality(self): + """Test basic YAML parsing functionality.""" + # create a temporary directory with test yaml files + with tempfile.TemporaryDirectory() as temp_dir: + test_yaml_content = { + 'seclab-taskflow-agent': { + 'type': 'taskflow', + 'version': 1 + }, + 'taskflow': [ + { + 'task': { + 'agents': ['assistant'], + 'user_prompt': 'Test prompt' + } + } + ] + } + + test_file = Path(temp_dir) / 'test_taskflow.yaml' + with open(test_file, 'w') as f: + yaml.dump(test_yaml_content, f) + + # Test parsing + parser = YamlParser(temp_dir) + result = parser.get_yaml_dict(recurse=False) + + assert 'test_taskflow' in result + assert result['test_taskflow']['seclab-taskflow-agent']['type'] == 'taskflow' + assert len(result['test_taskflow']['taskflow']) == 1 + assert result['test_taskflow']['taskflow'][0]['task']['agents'] == ['assistant'] + + +class TestRealTaskflowFiles: + """Test parsing of actual taskflow files in the project.""" + + def test_parse_example_taskflows(self): + """Test parsing the actual example taskflow files.""" + # this test uses the actual taskflows in the project + parser = YamlParser('taskflows/examples') + result = parser.get_yaml_dict() + + # should contain example files + assert len(result) > 0 + + # check that example.yaml is parsed correctly + example_task_flow = result['example'] + assert 'taskflow' in example_task_flow + assert isinstance(example_task_flow['taskflow'], list) + assert len(example_task_flow['taskflow']) == 4 # 4 tasks in taskflow + assert example_task_flow['taskflow'][0]['task']['max_steps'] == 20 + + def test_parse_all_taskflows(self): + """Test parsing all example taskflow files in the project.""" + parser = YamlParser('taskflows') + result = parser.get_yaml_dict(recurse=True, dir_namespace=True) + + # should contain all taskflow files (including subdirs) + assert len(result) == 13 + + # check access for files with namespacing + example_files = [key for key in result.keys() if key.startswith('examples/')] + assert len(example_files) > 0 + + +if __name__ == '__main__': + pytest.main([__file__, '-v']) \ No newline at end of file From bca70e45209c1827030d9ab7c26f0c5022a9282c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20St=C3=B6ckli?= Date: Tue, 21 Oct 2025 17:02:14 +0000 Subject: [PATCH 2/2] adapt tests to new constructor --- tests/test_yaml_parser.py | 41 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/tests/test_yaml_parser.py b/tests/test_yaml_parser.py index 8111d1c..b9d1a42 100644 --- a/tests/test_yaml_parser.py +++ b/tests/test_yaml_parser.py @@ -18,6 +18,7 @@ def test_yaml_parser_basic_functionality(self): """Test basic YAML parsing functionality.""" # create a temporary directory with test yaml files with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) test_yaml_content = { 'seclab-taskflow-agent': { 'type': 'taskflow', @@ -33,18 +34,19 @@ def test_yaml_parser_basic_functionality(self): ] } - test_file = Path(temp_dir) / 'test_taskflow.yaml' + test_file = temp_path / 'test_taskflow.yaml' with open(test_file, 'w') as f: yaml.dump(test_yaml_content, f) - # Test parsing - parser = YamlParser(temp_dir) - result = parser.get_yaml_dict(recurse=False) + parser = YamlParser(temp_path) + # get all yaml files in the directory + yaml_files = temp_path.glob('*.yaml') + result = parser.get_yaml_dict(yaml_files) - assert 'test_taskflow' in result - assert result['test_taskflow']['seclab-taskflow-agent']['type'] == 'taskflow' - assert len(result['test_taskflow']['taskflow']) == 1 - assert result['test_taskflow']['taskflow'][0]['task']['agents'] == ['assistant'] + assert 'test_taskflow.yaml' in result + assert result['test_taskflow.yaml']['seclab-taskflow-agent']['type'] == 'taskflow' + assert len(result['test_taskflow.yaml']['taskflow']) == 1 + assert result['test_taskflow.yaml']['taskflow'][0]['task']['agents'] == ['assistant'] class TestRealTaskflowFiles: @@ -53,29 +55,36 @@ class TestRealTaskflowFiles: def test_parse_example_taskflows(self): """Test parsing the actual example taskflow files.""" # this test uses the actual taskflows in the project - parser = YamlParser('taskflows/examples') - result = parser.get_yaml_dict() + examples_path = Path('taskflows/examples').absolute() + parser = YamlParser(examples_path) + + # Get all YAML files in the examples directory + yaml_files = examples_path.glob('*.yaml') + result = parser.get_yaml_dict(yaml_files) # should contain example files assert len(result) > 0 # check that example.yaml is parsed correctly - example_task_flow = result['example'] + example_task_flow = result['example.yaml'] assert 'taskflow' in example_task_flow assert isinstance(example_task_flow['taskflow'], list) - assert len(example_task_flow['taskflow']) == 4 # 4 tasks in taskflow + assert len(example_task_flow['taskflow']) == 4 # 4 tasks in taskflow assert example_task_flow['taskflow'][0]['task']['max_steps'] == 20 def test_parse_all_taskflows(self): """Test parsing all example taskflow files in the project.""" - parser = YamlParser('taskflows') - result = parser.get_yaml_dict(recurse=True, dir_namespace=True) + taskflows_path = Path('taskflows').absolute() + parser = YamlParser(taskflows_path) + + yaml_files = taskflows_path.rglob('*.yaml') + result = parser.get_yaml_dict(yaml_files) # should contain all taskflow files (including subdirs) assert len(result) == 13 - # check access for files with namespacing - example_files = [key for key in result.keys() if key.startswith('examples/')] + # check access for files with directory structure in names + example_files = [key for key in result.keys() if 'examples/' in key] assert len(example_files) > 0