From f29a51dbabd0a8a0dc729a0ab38f90f4885c612a Mon Sep 17 00:00:00 2001 From: Didier Durand Date: Sat, 13 Dec 2025 07:34:53 +0100 Subject: [PATCH 1/8] [TEST] adding tests for ID Generator and associated classes --- tests/server/test_id_generator.py | 167 ++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/server/test_id_generator.py diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py new file mode 100644 index 00000000..8481233a --- /dev/null +++ b/tests/server/test_id_generator.py @@ -0,0 +1,167 @@ +import uuid +from unittest.mock import patch + +import pytest + +from a2a.server.id_generator import IDGeneratorContext, IDGenerator, UUIDGenerator + + +class TestIDGeneratorContext: + """Tests for IDGeneratorContext.""" + + def test_context_creation_with_all_fields(self): + """Test creating context with all fields populated.""" + context = IDGeneratorContext(task_id="task_123", context_id="context_456") + assert context.task_id == "task_123" + assert context.context_id == "context_456" + + def test_context_creation_with_defaults(self): + """Test creating context with default None values.""" + context = IDGeneratorContext() + assert context.task_id is None + assert context.context_id is None + + def test_context_creation_with_partial_fields(self): + """Test creating context with only some fields populated.""" + context = IDGeneratorContext(task_id="task_123") + assert context.task_id == "task_123" + assert context.context_id is None + + def test_context_mutability(self): + """Test that context fields can be updated (Pydantic models are mutable by default).""" + context = IDGeneratorContext(task_id="task_123") + context.task_id = "task_456" + assert context.task_id == "task_456" + + def test_context_validation(self): + """Test that context validates field types.""" + context = IDGeneratorContext(task_id="valid_string") + assert isinstance(context.task_id, str) + + +class TestIDGenerator: + """Tests for IDGenerator abstract base class.""" + + def test_cannot_instantiate_abstract_class(self): + """Test that IDGenerator cannot be instantiated directly.""" + with pytest.raises(TypeError): + IDGenerator() # noqa + + def test_subclass_must_implement_generate(self): + """Test that subclasses must implement the generate method.""" + + class IncompleteGenerator(IDGenerator): # noqa + pass + + with pytest.raises(TypeError): + IncompleteGenerator() # noqa + + def test_valid_subclass_implementation(self): + """Test that a valid subclass can be instantiated.""" + + class ValidGenerator(IDGenerator): + def generate(self, context: IDGeneratorContext) -> str: + return "test_id" + + generator = ValidGenerator() + assert generator.generate(IDGeneratorContext()) == "test_id" + + +class TestUUIDGenerator: + """Tests for UUIDGenerator implementation.""" + + def test_generate_returns_string(self): + """Test that generate returns a string.""" + generator = UUIDGenerator() + context = IDGeneratorContext() + result = generator.generate(context) + assert isinstance(result, str) + + def test_generate_returns_valid_uuid(self): + """Test that generate returns a valid UUID format.""" + generator = UUIDGenerator() + context = IDGeneratorContext() + result = generator.generate(context) + + # This should not raise an exception if result is a valid UUID + uuid.UUID(result) + + def test_generate_returns_uuid_version_4(self): + """Test that generate returns a UUID version 4.""" + generator = UUIDGenerator() + context = IDGeneratorContext() + result = generator.generate(context) + + parsed_uuid = uuid.UUID(result) + assert parsed_uuid.version == 4 + + def test_generate_ignores_context(self): + """Test that generate ignores the context parameter.""" + generator = UUIDGenerator() + context1 = IDGeneratorContext(task_id="task_1", context_id="context_1") + context2 = IDGeneratorContext(task_id="task_2", context_id="context_2") + + result1 = generator.generate(context1) + result2 = generator.generate(context2) + + # Both should be valid UUIDs but different + uuid.UUID(result1) + uuid.UUID(result2) + assert result1 != result2 + + def test_generate_produces_unique_ids(self): + """Test that multiple calls produce unique IDs.""" + generator = UUIDGenerator() + context = IDGeneratorContext() + + ids = [generator.generate(context) for _ in range(100)] + + # All IDs should be unique + assert len(ids) == len(set(ids)) + + def test_generate_with_empty_context(self): + """Test that generate works with an empty context.""" + generator = UUIDGenerator() + context = IDGeneratorContext() + result = generator.generate(context) + + assert isinstance(result, str) + uuid.UUID(result) + + def test_generate_with_populated_context(self): + """Test that generate works with a populated context.""" + generator = UUIDGenerator() + context = IDGeneratorContext(task_id="task_123", context_id="context_456") + result = generator.generate(context) + + assert isinstance(result, str) + uuid.UUID(result) + + @patch('uuid.uuid4') + def test_generate_calls_uuid4(self, mock_uuid4): + """Test that generate uses uuid.uuid4() internally.""" + mock_uuid = uuid.UUID('12345678-1234-5678-1234-567812345678') + mock_uuid4.return_value = mock_uuid + + generator = UUIDGenerator() + context = IDGeneratorContext() + result = generator.generate(context) + + mock_uuid4.assert_called_once() + assert result == str(mock_uuid) + + def test_generator_is_instance_of_id_generator(self): + """Test that UUIDGenerator is an instance of IDGenerator.""" + generator = UUIDGenerator() + assert isinstance(generator, IDGenerator) + + def test_multiple_generators_produce_different_ids(self): + """Test that multiple generator instances produce different IDs.""" + generator1 = UUIDGenerator() + generator2 = UUIDGenerator() + context = IDGeneratorContext() + + result1 = generator1.generate(context) + result2 = generator2.generate(context) + + assert result1 != result2 \ No newline at end of file From 8302509d468d227233ec5e55ceebf968427a42bd Mon Sep 17 00:00:00 2001 From: Didier Durand <2927957+didier-durand@users.noreply.github.com> Date: Sat, 13 Dec 2025 07:43:37 +0100 Subject: [PATCH 2/8] Update tests/server/test_id_generator.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- tests/server/test_id_generator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 8481233a..39e294fc 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -83,7 +83,6 @@ def test_generate_returns_valid_uuid(self): context = IDGeneratorContext() result = generator.generate(context) - # This should not raise an exception if result is a valid UUID uuid.UUID(result) def test_generate_returns_uuid_version_4(self): From b1bdd8970212e2b665d2e7ffa6d35e42fd214fd7 Mon Sep 17 00:00:00 2001 From: Didier Durand <2927957+didier-durand@users.noreply.github.com> Date: Sat, 13 Dec 2025 07:44:01 +0100 Subject: [PATCH 3/8] Update tests/server/test_id_generator.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- tests/server/test_id_generator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 39e294fc..af55da1b 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -103,7 +103,6 @@ def test_generate_ignores_context(self): result1 = generator.generate(context1) result2 = generator.generate(context2) - # Both should be valid UUIDs but different uuid.UUID(result1) uuid.UUID(result2) assert result1 != result2 From f6d99a294ca562e8819b2fe72fe9374fe87e67ee Mon Sep 17 00:00:00 2001 From: Didier Durand <2927957+didier-durand@users.noreply.github.com> Date: Sat, 13 Dec 2025 07:46:22 +0100 Subject: [PATCH 4/8] Update tests/server/test_id_generator.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- tests/server/test_id_generator.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index af55da1b..35a53f72 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -34,9 +34,11 @@ def test_context_mutability(self): assert context.task_id == "task_456" def test_context_validation(self): - """Test that context validates field types.""" - context = IDGeneratorContext(task_id="valid_string") - assert isinstance(context.task_id, str) + """Test that context raises validation error for invalid types.""" + from pydantic import ValidationError + + with pytest.raises(ValidationError): + IDGeneratorContext(task_id={"not": "a string"}) class TestIDGenerator: From 00a442f72e9043e2647f0a4aa5174f00dae80f71 Mon Sep 17 00:00:00 2001 From: Didier Durand Date: Sat, 13 Dec 2025 08:09:25 +0100 Subject: [PATCH 5/8] test: fixing pylint issues --- tests/server/test_id_generator.py | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 35a53f72..6124b07e 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -1,3 +1,4 @@ +"""Tests for IDGenerator abstract base class.""" import uuid from unittest.mock import patch @@ -35,10 +36,10 @@ def test_context_mutability(self): def test_context_validation(self): """Test that context raises validation error for invalid types.""" - from pydantic import ValidationError + from pydantic import ValidationError # pylint: disable=C0415 with pytest.raises(ValidationError): - IDGeneratorContext(task_id={"not": "a string"}) + IDGeneratorContext(task_id={"not": "a string"}) # noqa class TestIDGenerator: @@ -47,24 +48,22 @@ class TestIDGenerator: def test_cannot_instantiate_abstract_class(self): """Test that IDGenerator cannot be instantiated directly.""" with pytest.raises(TypeError): - IDGenerator() # noqa + IDGenerator() # noqa pylint: disable=E0110 def test_subclass_must_implement_generate(self): """Test that subclasses must implement the generate method.""" - - class IncompleteGenerator(IDGenerator): # noqa + + class IncompleteGenerator(IDGenerator): # noqa pylint: disable=C0115,R0903 pass with pytest.raises(TypeError): - IncompleteGenerator() # noqa + IncompleteGenerator() # noqa pylint: disable=E0110 def test_valid_subclass_implementation(self): """Test that a valid subclass can be instantiated.""" - - class ValidGenerator(IDGenerator): + class ValidGenerator(IDGenerator): # pylint: disable=C0115,R0903 def generate(self, context: IDGeneratorContext) -> str: return "test_id" - generator = ValidGenerator() assert generator.generate(IDGeneratorContext()) == "test_id" @@ -84,7 +83,6 @@ def test_generate_returns_valid_uuid(self): generator = UUIDGenerator() context = IDGeneratorContext() result = generator.generate(context) - uuid.UUID(result) def test_generate_returns_uuid_version_4(self): @@ -92,7 +90,6 @@ def test_generate_returns_uuid_version_4(self): generator = UUIDGenerator() context = IDGeneratorContext() result = generator.generate(context) - parsed_uuid = uuid.UUID(result) assert parsed_uuid.version == 4 @@ -101,10 +98,8 @@ def test_generate_ignores_context(self): generator = UUIDGenerator() context1 = IDGeneratorContext(task_id="task_1", context_id="context_1") context2 = IDGeneratorContext(task_id="task_2", context_id="context_2") - result1 = generator.generate(context1) result2 = generator.generate(context2) - uuid.UUID(result1) uuid.UUID(result2) assert result1 != result2 @@ -113,9 +108,7 @@ def test_generate_produces_unique_ids(self): """Test that multiple calls produce unique IDs.""" generator = UUIDGenerator() context = IDGeneratorContext() - ids = [generator.generate(context) for _ in range(100)] - # All IDs should be unique assert len(ids) == len(set(ids)) @@ -124,7 +117,6 @@ def test_generate_with_empty_context(self): generator = UUIDGenerator() context = IDGeneratorContext() result = generator.generate(context) - assert isinstance(result, str) uuid.UUID(result) @@ -133,7 +125,6 @@ def test_generate_with_populated_context(self): generator = UUIDGenerator() context = IDGeneratorContext(task_id="task_123", context_id="context_456") result = generator.generate(context) - assert isinstance(result, str) uuid.UUID(result) @@ -142,11 +133,9 @@ def test_generate_calls_uuid4(self, mock_uuid4): """Test that generate uses uuid.uuid4() internally.""" mock_uuid = uuid.UUID('12345678-1234-5678-1234-567812345678') mock_uuid4.return_value = mock_uuid - generator = UUIDGenerator() context = IDGeneratorContext() result = generator.generate(context) - mock_uuid4.assert_called_once() assert result == str(mock_uuid) @@ -160,8 +149,6 @@ def test_multiple_generators_produce_different_ids(self): generator1 = UUIDGenerator() generator2 = UUIDGenerator() context = IDGeneratorContext() - result1 = generator1.generate(context) result2 = generator2.generate(context) - - assert result1 != result2 \ No newline at end of file + assert result1 != result2 From 6877dd40779e189d2495d6a92d951165a78180b5 Mon Sep 17 00:00:00 2001 From: Didier Durand Date: Sat, 13 Dec 2025 08:40:40 +0100 Subject: [PATCH 6/8] test: reformatting code for lint --- tests/server/test_id_generator.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 6124b07e..3b7c833f 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -39,7 +39,7 @@ def test_context_validation(self): from pydantic import ValidationError # pylint: disable=C0415 with pytest.raises(ValidationError): - IDGeneratorContext(task_id={"not": "a string"}) # noqa + IDGeneratorContext(task_id={"not": "a string"}) # noqa class TestIDGenerator: @@ -48,22 +48,24 @@ class TestIDGenerator: def test_cannot_instantiate_abstract_class(self): """Test that IDGenerator cannot be instantiated directly.""" with pytest.raises(TypeError): - IDGenerator() # noqa pylint: disable=E0110 + IDGenerator() # noqa pylint: disable=E0110 def test_subclass_must_implement_generate(self): """Test that subclasses must implement the generate method.""" - class IncompleteGenerator(IDGenerator): # noqa pylint: disable=C0115,R0903 + class IncompleteGenerator(IDGenerator): # noqa pylint: disable=C0115,R0903 pass with pytest.raises(TypeError): - IncompleteGenerator() # noqa pylint: disable=E0110 + IncompleteGenerator() # noqa pylint: disable=E0110 def test_valid_subclass_implementation(self): """Test that a valid subclass can be instantiated.""" - class ValidGenerator(IDGenerator): # pylint: disable=C0115,R0903 + + class ValidGenerator(IDGenerator): # pylint: disable=C0115,R0903 def generate(self, context: IDGeneratorContext) -> str: return "test_id" + generator = ValidGenerator() assert generator.generate(IDGeneratorContext()) == "test_id" From 2afc4a03263f2feb47bfec729ebc86064c6d64f3 Mon Sep 17 00:00:00 2001 From: Didier Durand Date: Sat, 13 Dec 2025 08:48:48 +0100 Subject: [PATCH 7/8] test: fix ruff issues --- tests/server/test_id_generator.py | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 3b7c833f..28b35667 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -1,10 +1,17 @@ """Tests for IDGenerator abstract base class.""" import uuid + from unittest.mock import patch import pytest -from a2a.server.id_generator import IDGeneratorContext, IDGenerator, UUIDGenerator +from pydantic import ValidationError + +from a2a.server.id_generator import ( + IDGenerator, + IDGeneratorContext, + UUIDGenerator, +) class TestIDGeneratorContext: @@ -12,9 +19,9 @@ class TestIDGeneratorContext: def test_context_creation_with_all_fields(self): """Test creating context with all fields populated.""" - context = IDGeneratorContext(task_id="task_123", context_id="context_456") - assert context.task_id == "task_123" - assert context.context_id == "context_456" + context = IDGeneratorContext(task_id='task_123', context_id='context_456') + assert context.task_id == 'task_123' + assert context.context_id == 'context_456' def test_context_creation_with_defaults(self): """Test creating context with default None values.""" @@ -24,20 +31,18 @@ def test_context_creation_with_defaults(self): def test_context_creation_with_partial_fields(self): """Test creating context with only some fields populated.""" - context = IDGeneratorContext(task_id="task_123") - assert context.task_id == "task_123" + context = IDGeneratorContext(task_id='task_123') + assert context.task_id == 'task_123' assert context.context_id is None def test_context_mutability(self): """Test that context fields can be updated (Pydantic models are mutable by default).""" - context = IDGeneratorContext(task_id="task_123") - context.task_id = "task_456" - assert context.task_id == "task_456" + context = IDGeneratorContext(task_id='task_123') + context.task_id = 'task_456' + assert context.task_id == 'task_456' def test_context_validation(self): """Test that context raises validation error for invalid types.""" - from pydantic import ValidationError # pylint: disable=C0415 - with pytest.raises(ValidationError): IDGeneratorContext(task_id={"not": "a string"}) # noqa @@ -48,26 +53,26 @@ class TestIDGenerator: def test_cannot_instantiate_abstract_class(self): """Test that IDGenerator cannot be instantiated directly.""" with pytest.raises(TypeError): - IDGenerator() # noqa pylint: disable=E0110 + IDGenerator() def test_subclass_must_implement_generate(self): """Test that subclasses must implement the generate method.""" - class IncompleteGenerator(IDGenerator): # noqa pylint: disable=C0115,R0903 + class IncompleteGenerator(IDGenerator): pass with pytest.raises(TypeError): - IncompleteGenerator() # noqa pylint: disable=E0110 + IncompleteGenerator() def test_valid_subclass_implementation(self): """Test that a valid subclass can be instantiated.""" class ValidGenerator(IDGenerator): # pylint: disable=C0115,R0903 def generate(self, context: IDGeneratorContext) -> str: - return "test_id" + return 'test_id' generator = ValidGenerator() - assert generator.generate(IDGeneratorContext()) == "test_id" + assert generator.generate(IDGeneratorContext()) == 'test_id' class TestUUIDGenerator: @@ -98,8 +103,8 @@ def test_generate_returns_uuid_version_4(self): def test_generate_ignores_context(self): """Test that generate ignores the context parameter.""" generator = UUIDGenerator() - context1 = IDGeneratorContext(task_id="task_1", context_id="context_1") - context2 = IDGeneratorContext(task_id="task_2", context_id="context_2") + context1 = IDGeneratorContext(task_id='task_1', context_id='context_1') + context2 = IDGeneratorContext(task_id='task_2', context_id='context_2') result1 = generator.generate(context1) result2 = generator.generate(context2) uuid.UUID(result1) @@ -125,7 +130,7 @@ def test_generate_with_empty_context(self): def test_generate_with_populated_context(self): """Test that generate works with a populated context.""" generator = UUIDGenerator() - context = IDGeneratorContext(task_id="task_123", context_id="context_456") + context = IDGeneratorContext(task_id='task_123', context_id='context_456') result = generator.generate(context) assert isinstance(result, str) uuid.UUID(result) From 7450e9a4d9facb15bedc79c1e46fbc797a09be81 Mon Sep 17 00:00:00 2001 From: Didier Durand Date: Sat, 13 Dec 2025 08:58:53 +0100 Subject: [PATCH 8/8] test: executed `ruff format` on new code --- tests/server/test_id_generator.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/server/test_id_generator.py b/tests/server/test_id_generator.py index 28b35667..3a842e6a 100644 --- a/tests/server/test_id_generator.py +++ b/tests/server/test_id_generator.py @@ -1,4 +1,5 @@ """Tests for IDGenerator abstract base class.""" + import uuid from unittest.mock import patch @@ -19,7 +20,9 @@ class TestIDGeneratorContext: def test_context_creation_with_all_fields(self): """Test creating context with all fields populated.""" - context = IDGeneratorContext(task_id='task_123', context_id='context_456') + context = IDGeneratorContext( + task_id='task_123', context_id='context_456' + ) assert context.task_id == 'task_123' assert context.context_id == 'context_456' @@ -44,7 +47,7 @@ def test_context_mutability(self): def test_context_validation(self): """Test that context raises validation error for invalid types.""" with pytest.raises(ValidationError): - IDGeneratorContext(task_id={"not": "a string"}) # noqa + IDGeneratorContext(task_id={'not': 'a string'}) # noqa class TestIDGenerator: @@ -130,7 +133,9 @@ def test_generate_with_empty_context(self): def test_generate_with_populated_context(self): """Test that generate works with a populated context.""" generator = UUIDGenerator() - context = IDGeneratorContext(task_id='task_123', context_id='context_456') + context = IDGeneratorContext( + task_id='task_123', context_id='context_456' + ) result = generator.generate(context) assert isinstance(result, str) uuid.UUID(result)