chore: Make UT of a2a consistent about how tests should be skipped when python verison < 3.10

PiperOrigin-RevId: 801040421
This commit is contained in:
Xiang (Sean) Zhou
2025-08-29 14:59:27 -07:00
committed by Copybara-Service
parent 2eddc5e4d3
commit 98b0426cd2
11 changed files with 197 additions and 323 deletions
+76 -9
View File
@@ -14,17 +14,84 @@
from unittest.mock import MagicMock
from google.adk.agents.invocation_context import InvocationContext
from google.adk.agents.langgraph_agent import LangGraphAgent
from google.adk.events.event import Event
from google.adk.plugins.plugin_manager import PluginManager
from google.genai import types
from langchain_core.messages import AIMessage
from langchain_core.messages import HumanMessage
from langchain_core.messages import SystemMessage
from langgraph.graph.graph import CompiledGraph
import pytest
# Skip all tests in this module if LangGraph dependencies are not available
LANGGRAPH_AVAILABLE = True
try:
from google.adk.agents.invocation_context import InvocationContext
from google.adk.agents.langgraph_agent import LangGraphAgent
from google.adk.events.event import Event
from google.adk.plugins.plugin_manager import PluginManager
from google.genai import types
from langchain_core.messages import AIMessage
from langchain_core.messages import HumanMessage
from langchain_core.messages import SystemMessage
from langgraph.graph.graph import CompiledGraph
except ImportError:
LANGGRAPH_AVAILABLE = False
# IMPORTANT: Dummy classes are REQUIRED in this file but NOT in A2A test files.
# Here's why this file is different from A2A test files:
#
# 1. MODULE-LEVEL USAGE IN DECORATORS:
# This file uses @pytest.mark.parametrize decorator with complex nested structures
# that directly reference imported types like Event(), types.Content(), types.Part.from_text().
# These decorator expressions are evaluated during MODULE COMPILATION TIME,
# not during test execution time.
#
# 2. A2A TEST FILES PATTERN:
# Most A2A test files only use imported types within test method bodies:
# - Inside test functions: def test_something(): Message(...)
# - These are evaluated during TEST EXECUTION TIME when tests are skipped
# - No NameError occurs because skipped tests don't execute their bodies
#
# 3. WHAT HAPPENS WITHOUT DUMMIES:
# If we remove dummy classes from this file:
# - Python tries to compile the @pytest.mark.parametrize decorator
# - It encounters Event(...), types.Content(...), etc.
# - These names are undefined → NameError during module compilation
# - Test collection fails before pytest.mark.skipif can even run
#
# 4. WHY DUMMIES WORK:
# - DummyTypes() can be called like Event() → returns DummyTypes instance
# - DummyTypes.__getattr__ handles types.Content → returns DummyTypes instance
# - DummyTypes.__call__ handles types.Part.from_text() → returns DummyTypes instance
# - The parametrize decorator gets dummy objects instead of real ones
# - Tests still get skipped due to pytestmark, so dummies never actually run
#
# 5. EXCEPTION CASES IN A2A FILES:
# A few A2A files DID need dummies initially because they had:
# - Type annotations: def create_helper(x: str) -> Message
# - But we removed those type annotations to eliminate the need for dummies
#
# This file cannot avoid dummies because the parametrize decorator usage
# is fundamental to the test structure and cannot be easily refactored.
class DummyTypes:
def __getattr__(self, name):
return DummyTypes()
def __call__(self, *args, **kwargs):
return DummyTypes()
InvocationContext = DummyTypes()
LangGraphAgent = DummyTypes()
Event = DummyTypes()
PluginManager = DummyTypes()
types = (
DummyTypes()
) # Must support chained calls like types.Content(), types.Part.from_text()
AIMessage = DummyTypes()
HumanMessage = DummyTypes()
SystemMessage = DummyTypes()
CompiledGraph = DummyTypes()
pytestmark = pytest.mark.skipif(
not LANGGRAPH_AVAILABLE, reason="LangGraph dependencies not available"
)
@pytest.mark.parametrize(
"checkpointer_value, events_list, expected_messages",