google-adk 0.0.3__py3-none-any.whl → 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/adk/agents/run_config.py +4 -0
- google/adk/auth/auth_preprocessor.py +19 -16
- google/adk/cli/browser/index.html +1 -1
- google/adk/cli/browser/{main-SY2WYYGV.js → main-CU22TRPI.js} +30 -30
- google/adk/cli/cli.py +8 -8
- google/adk/cli/cli_deploy.py +2 -4
- google/adk/cli/cli_tools_click.py +6 -6
- google/adk/flows/llm_flows/contents.py +21 -1
- google/adk/flows/llm_flows/functions.py +3 -1
- google/adk/models/google_llm.py +0 -1
- google/adk/runners.py +13 -2
- google/adk/version.py +1 -1
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/METADATA +4 -2
- google_adk-0.0.4.dist-info/RECORD +175 -0
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/WHEEL +1 -1
- google_adk-0.0.4.dist-info/licenses/LICENSE +202 -0
- google/adk/._version.py +0 -0
- google/adk/docs/Makefile +0 -20
- google/adk/docs/build/doctrees/google-adk.doctree +0 -0
- google/adk/docs/build/html/_sources/google-adk.rst.txt +0 -98
- google/adk/docs/build/html/_sources/index.rst.txt +0 -7
- google/adk/docs/build/html/_static/autodoc_pydantic.css +0 -27
- google/adk/docs/build/html/_static/basic.css +0 -925
- google/adk/docs/build/html/_static/debug.css +0 -85
- google/adk/docs/build/html/_static/doctools.js +0 -156
- google/adk/docs/build/html/_static/documentation_options.js +0 -29
- google/adk/docs/build/html/_static/file.png +0 -0
- google/adk/docs/build/html/_static/language_data.js +0 -199
- google/adk/docs/build/html/_static/minus.png +0 -0
- google/adk/docs/build/html/_static/plus.png +0 -0
- google/adk/docs/build/html/_static/pygments.css +0 -274
- google/adk/docs/build/html/_static/scripts/furo-extensions.js +0 -16
- google/adk/docs/build/html/_static/scripts/furo.js +0 -19
- google/adk/docs/build/html/_static/scripts/furo.js.LICENSE.txt +0 -7
- google/adk/docs/build/html/_static/scripts/furo.js.map +0 -1
- google/adk/docs/build/html/_static/searchtools.js +0 -620
- google/adk/docs/build/html/_static/skeleton.css +0 -312
- google/adk/docs/build/html/_static/sphinx_highlight.js +0 -170
- google/adk/docs/build/html/_static/styles/furo-extensions.css +0 -18
- google/adk/docs/build/html/_static/styles/furo-extensions.css.map +0 -1
- google/adk/docs/build/html/_static/styles/furo.css +0 -18
- google/adk/docs/build/html/_static/styles/furo.css.map +0 -1
- google/adk/docs/build/html/genindex.html +0 -861
- google/adk/docs/build/html/google-adk.html +0 -5461
- google/adk/docs/build/html/index.html +0 -567
- google/adk/docs/build/html/objects.inv +0 -0
- google/adk/docs/build/html/py-modindex.html +0 -373
- google/adk/docs/build/html/search.html +0 -333
- google/adk/docs/build/html/searchindex.js +0 -17
- google/adk/docs/source/conf.py +0 -133
- google/adk/docs/source/google-adk.rst +0 -98
- google/adk/docs/source/index.rst +0 -7
- google/adk/tests/__init__.py +0 -14
- google/adk/tests/integration/.env.example +0 -10
- google/adk/tests/integration/__init__.py +0 -18
- google/adk/tests/integration/conftest.py +0 -119
- google/adk/tests/integration/fixture/__init__.py +0 -14
- google/adk/tests/integration/fixture/agent_with_config/__init__.py +0 -15
- google/adk/tests/integration/fixture/agent_with_config/agent.py +0 -88
- google/adk/tests/integration/fixture/callback_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/callback_agent/agent.py +0 -105
- google/adk/tests/integration/fixture/context_update_test/OWNERS +0 -1
- google/adk/tests/integration/fixture/context_update_test/__init__.py +0 -15
- google/adk/tests/integration/fixture/context_update_test/agent.py +0 -43
- google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +0 -582
- google/adk/tests/integration/fixture/context_variable_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/context_variable_agent/agent.py +0 -115
- google/adk/tests/integration/fixture/customer_support_ma/__init__.py +0 -15
- google/adk/tests/integration/fixture/customer_support_ma/agent.py +0 -172
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +0 -338
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +0 -69
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +0 -6
- google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +0 -15
- google/adk/tests/integration/fixture/flow_complex_spark/agent.py +0 -182
- google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +0 -190
- google/adk/tests/integration/fixture/hello_world_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/hello_world_agent/agent.py +0 -95
- google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +0 -24
- google/adk/tests/integration/fixture/hello_world_agent/test_config.json +0 -6
- google/adk/tests/integration/fixture/home_automation_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/home_automation_agent/agent.py +0 -304
- google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_config.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +0 -18
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +0 -17
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +0 -6
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +0 -18
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +0 -17
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +0 -5
- google/adk/tests/integration/fixture/tool_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/tool_agent/agent.py +0 -218
- google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
- google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/trip_planner_agent/agent.py +0 -110
- google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +0 -13
- google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +0 -5
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +0 -13
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +0 -5
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +0 -7
- google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +0 -19
- google/adk/tests/integration/models/__init__.py +0 -14
- google/adk/tests/integration/models/test_google_llm.py +0 -65
- google/adk/tests/integration/test_callback.py +0 -70
- google/adk/tests/integration/test_context_variable.py +0 -67
- google/adk/tests/integration/test_evalute_agent_in_fixture.py +0 -76
- google/adk/tests/integration/test_multi_agent.py +0 -28
- google/adk/tests/integration/test_multi_turn.py +0 -42
- google/adk/tests/integration/test_single_agent.py +0 -23
- google/adk/tests/integration/test_sub_agent.py +0 -26
- google/adk/tests/integration/test_system_instruction.py +0 -177
- google/adk/tests/integration/test_tools.py +0 -287
- google/adk/tests/integration/test_with_test_file.py +0 -34
- google/adk/tests/integration/tools/__init__.py +0 -14
- google/adk/tests/integration/utils/__init__.py +0 -16
- google/adk/tests/integration/utils/asserts.py +0 -75
- google/adk/tests/integration/utils/test_runner.py +0 -97
- google/adk/tests/unittests/__init__.py +0 -14
- google/adk/tests/unittests/agents/__init__.py +0 -14
- google/adk/tests/unittests/agents/test_base_agent.py +0 -407
- google/adk/tests/unittests/agents/test_langgraph_agent.py +0 -191
- google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +0 -138
- google/adk/tests/unittests/agents/test_llm_agent_fields.py +0 -231
- google/adk/tests/unittests/agents/test_loop_agent.py +0 -136
- google/adk/tests/unittests/agents/test_parallel_agent.py +0 -92
- google/adk/tests/unittests/agents/test_sequential_agent.py +0 -114
- google/adk/tests/unittests/artifacts/__init__.py +0 -14
- google/adk/tests/unittests/artifacts/test_artifact_service.py +0 -276
- google/adk/tests/unittests/auth/test_auth_handler.py +0 -575
- google/adk/tests/unittests/conftest.py +0 -73
- google/adk/tests/unittests/fast_api/__init__.py +0 -14
- google/adk/tests/unittests/fast_api/test_fast_api.py +0 -269
- google/adk/tests/unittests/flows/__init__.py +0 -14
- google/adk/tests/unittests/flows/llm_flows/__init__.py +0 -14
- google/adk/tests/unittests/flows/llm_flows/_test_examples.py +0 -142
- google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +0 -311
- google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +0 -244
- google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +0 -346
- google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +0 -93
- google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +0 -258
- google/adk/tests/unittests/flows/llm_flows/test_identity.py +0 -66
- google/adk/tests/unittests/flows/llm_flows/test_instructions.py +0 -164
- google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +0 -142
- google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +0 -46
- google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +0 -269
- google/adk/tests/unittests/models/__init__.py +0 -14
- google/adk/tests/unittests/models/test_google_llm.py +0 -224
- google/adk/tests/unittests/models/test_litellm.py +0 -804
- google/adk/tests/unittests/models/test_models.py +0 -60
- google/adk/tests/unittests/sessions/__init__.py +0 -14
- google/adk/tests/unittests/sessions/test_session_service.py +0 -227
- google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +0 -246
- google/adk/tests/unittests/streaming/__init__.py +0 -14
- google/adk/tests/unittests/streaming/test_streaming.py +0 -50
- google/adk/tests/unittests/tools/__init__.py +0 -14
- google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +0 -499
- google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +0 -204
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +0 -600
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +0 -630
- google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +0 -345
- google/adk/tests/unittests/tools/google_api_tool/__init__.py +0 -13
- google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +0 -657
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +0 -145
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +0 -68
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +0 -153
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +0 -196
- google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +0 -573
- google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +0 -436
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +0 -1367
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +0 -628
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +0 -139
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +0 -406
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +0 -966
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +0 -201
- google/adk/tests/unittests/tools/retrieval/__init__.py +0 -14
- google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +0 -147
- google/adk/tests/unittests/tools/test_agent_tool.py +0 -167
- google/adk/tests/unittests/tools/test_base_tool.py +0 -141
- google/adk/tests/unittests/tools/test_build_function_declaration.py +0 -277
- google/adk/tests/unittests/utils.py +0 -304
- google_adk-0.0.3.dist-info/RECORD +0 -340
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/entry_points.txt +0 -0
@@ -1,575 +0,0 @@
|
|
1
|
-
# Copyright 2025 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
import copy
|
16
|
-
from unittest.mock import patch
|
17
|
-
|
18
|
-
from fastapi.openapi.models import APIKey
|
19
|
-
from fastapi.openapi.models import APIKeyIn
|
20
|
-
from fastapi.openapi.models import OAuth2
|
21
|
-
from fastapi.openapi.models import OAuthFlowAuthorizationCode
|
22
|
-
from fastapi.openapi.models import OAuthFlows
|
23
|
-
from google.adk.auth.auth_credential import AuthCredential
|
24
|
-
from google.adk.auth.auth_credential import AuthCredentialTypes
|
25
|
-
from google.adk.auth.auth_credential import OAuth2Auth
|
26
|
-
from google.adk.auth.auth_handler import AuthHandler
|
27
|
-
from google.adk.auth.auth_schemes import OpenIdConnectWithConfig
|
28
|
-
from google.adk.auth.auth_tool import AuthConfig
|
29
|
-
import pytest
|
30
|
-
|
31
|
-
|
32
|
-
# Mock classes for testing
|
33
|
-
class MockState(dict):
|
34
|
-
"""Mock State class for testing."""
|
35
|
-
|
36
|
-
def __init__(self, *args, **kwargs):
|
37
|
-
super().__init__(*args, **kwargs)
|
38
|
-
|
39
|
-
def get(self, key, default=None):
|
40
|
-
return super().get(key, default)
|
41
|
-
|
42
|
-
|
43
|
-
class MockOAuth2Session:
|
44
|
-
"""Mock OAuth2Session for testing."""
|
45
|
-
|
46
|
-
def __init__(
|
47
|
-
self,
|
48
|
-
client_id=None,
|
49
|
-
client_secret=None,
|
50
|
-
scope=None,
|
51
|
-
redirect_uri=None,
|
52
|
-
state=None,
|
53
|
-
):
|
54
|
-
self.client_id = client_id
|
55
|
-
self.client_secret = client_secret
|
56
|
-
self.scope = scope
|
57
|
-
self.redirect_uri = redirect_uri
|
58
|
-
self.state = state
|
59
|
-
|
60
|
-
def create_authorization_url(self, url):
|
61
|
-
return f"{url}?client_id={self.client_id}&scope={self.scope}", "mock_state"
|
62
|
-
|
63
|
-
def fetch_token(
|
64
|
-
self,
|
65
|
-
token_endpoint,
|
66
|
-
authorization_response=None,
|
67
|
-
code=None,
|
68
|
-
grant_type=None,
|
69
|
-
):
|
70
|
-
return {
|
71
|
-
"access_token": "mock_access_token",
|
72
|
-
"token_type": "bearer",
|
73
|
-
"expires_in": 3600,
|
74
|
-
"refresh_token": "mock_refresh_token",
|
75
|
-
}
|
76
|
-
|
77
|
-
|
78
|
-
# Fixtures for common test objects
|
79
|
-
@pytest.fixture
|
80
|
-
def oauth2_auth_scheme():
|
81
|
-
"""Create an OAuth2 auth scheme for testing."""
|
82
|
-
# Create the OAuthFlows object first
|
83
|
-
flows = OAuthFlows(
|
84
|
-
authorizationCode=OAuthFlowAuthorizationCode(
|
85
|
-
authorizationUrl="https://example.com/oauth2/authorize",
|
86
|
-
tokenUrl="https://example.com/oauth2/token",
|
87
|
-
scopes={"read": "Read access", "write": "Write access"},
|
88
|
-
)
|
89
|
-
)
|
90
|
-
|
91
|
-
# Then create the OAuth2 object with the flows
|
92
|
-
return OAuth2(flows=flows)
|
93
|
-
|
94
|
-
|
95
|
-
@pytest.fixture
|
96
|
-
def openid_auth_scheme():
|
97
|
-
"""Create an OpenID Connect auth scheme for testing."""
|
98
|
-
return OpenIdConnectWithConfig(
|
99
|
-
openIdConnectUrl="https://example.com/.well-known/openid-configuration",
|
100
|
-
authorization_endpoint="https://example.com/oauth2/authorize",
|
101
|
-
token_endpoint="https://example.com/oauth2/token",
|
102
|
-
scopes=["openid", "profile", "email"],
|
103
|
-
)
|
104
|
-
|
105
|
-
|
106
|
-
@pytest.fixture
|
107
|
-
def oauth2_credentials():
|
108
|
-
"""Create OAuth2 credentials for testing."""
|
109
|
-
return AuthCredential(
|
110
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
111
|
-
oauth2=OAuth2Auth(
|
112
|
-
client_id="mock_client_id",
|
113
|
-
client_secret="mock_client_secret",
|
114
|
-
redirect_uri="https://example.com/callback",
|
115
|
-
),
|
116
|
-
)
|
117
|
-
|
118
|
-
|
119
|
-
@pytest.fixture
|
120
|
-
def oauth2_credentials_with_token():
|
121
|
-
"""Create OAuth2 credentials with a token for testing."""
|
122
|
-
return AuthCredential(
|
123
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
124
|
-
oauth2=OAuth2Auth(
|
125
|
-
client_id="mock_client_id",
|
126
|
-
client_secret="mock_client_secret",
|
127
|
-
redirect_uri="https://example.com/callback",
|
128
|
-
token={
|
129
|
-
"access_token": "mock_access_token",
|
130
|
-
"token_type": "bearer",
|
131
|
-
"expires_in": 3600,
|
132
|
-
"refresh_token": "mock_refresh_token",
|
133
|
-
},
|
134
|
-
),
|
135
|
-
)
|
136
|
-
|
137
|
-
|
138
|
-
@pytest.fixture
|
139
|
-
def oauth2_credentials_with_auth_uri():
|
140
|
-
"""Create OAuth2 credentials with an auth URI for testing."""
|
141
|
-
return AuthCredential(
|
142
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
143
|
-
oauth2=OAuth2Auth(
|
144
|
-
client_id="mock_client_id",
|
145
|
-
client_secret="mock_client_secret",
|
146
|
-
redirect_uri="https://example.com/callback",
|
147
|
-
auth_uri="https://example.com/oauth2/authorize?client_id=mock_client_id&scope=read,write",
|
148
|
-
state="mock_state",
|
149
|
-
),
|
150
|
-
)
|
151
|
-
|
152
|
-
|
153
|
-
@pytest.fixture
|
154
|
-
def oauth2_credentials_with_auth_code():
|
155
|
-
"""Create OAuth2 credentials with an auth code for testing."""
|
156
|
-
return AuthCredential(
|
157
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
158
|
-
oauth2=OAuth2Auth(
|
159
|
-
client_id="mock_client_id",
|
160
|
-
client_secret="mock_client_secret",
|
161
|
-
redirect_uri="https://example.com/callback",
|
162
|
-
auth_uri="https://example.com/oauth2/authorize?client_id=mock_client_id&scope=read,write",
|
163
|
-
state="mock_state",
|
164
|
-
auth_code="mock_auth_code",
|
165
|
-
auth_response_uri="https://example.com/callback?code=mock_auth_code&state=mock_state",
|
166
|
-
),
|
167
|
-
)
|
168
|
-
|
169
|
-
|
170
|
-
@pytest.fixture
|
171
|
-
def auth_config(oauth2_auth_scheme, oauth2_credentials):
|
172
|
-
"""Create an AuthConfig for testing."""
|
173
|
-
# Create a copy of the credentials for the exchanged_auth_credential
|
174
|
-
exchanged_credential = oauth2_credentials.model_copy(deep=True)
|
175
|
-
|
176
|
-
return AuthConfig(
|
177
|
-
auth_scheme=oauth2_auth_scheme,
|
178
|
-
raw_auth_credential=oauth2_credentials,
|
179
|
-
exchanged_auth_credential=exchanged_credential,
|
180
|
-
)
|
181
|
-
|
182
|
-
|
183
|
-
@pytest.fixture
|
184
|
-
def auth_config_with_exchanged(
|
185
|
-
oauth2_auth_scheme, oauth2_credentials, oauth2_credentials_with_auth_uri
|
186
|
-
):
|
187
|
-
"""Create an AuthConfig with exchanged credentials for testing."""
|
188
|
-
return AuthConfig(
|
189
|
-
auth_scheme=oauth2_auth_scheme,
|
190
|
-
raw_auth_credential=oauth2_credentials,
|
191
|
-
exchanged_auth_credential=oauth2_credentials_with_auth_uri,
|
192
|
-
)
|
193
|
-
|
194
|
-
|
195
|
-
@pytest.fixture
|
196
|
-
def auth_config_with_auth_code(
|
197
|
-
oauth2_auth_scheme, oauth2_credentials, oauth2_credentials_with_auth_code
|
198
|
-
):
|
199
|
-
"""Create an AuthConfig with auth code for testing."""
|
200
|
-
return AuthConfig(
|
201
|
-
auth_scheme=oauth2_auth_scheme,
|
202
|
-
raw_auth_credential=oauth2_credentials,
|
203
|
-
exchanged_auth_credential=oauth2_credentials_with_auth_code,
|
204
|
-
)
|
205
|
-
|
206
|
-
|
207
|
-
class TestAuthHandlerInit:
|
208
|
-
"""Tests for the AuthHandler initialization."""
|
209
|
-
|
210
|
-
def test_init(self, auth_config):
|
211
|
-
"""Test the initialization of AuthHandler."""
|
212
|
-
handler = AuthHandler(auth_config)
|
213
|
-
assert handler.auth_config == auth_config
|
214
|
-
|
215
|
-
|
216
|
-
class TestGetCredentialKey:
|
217
|
-
"""Tests for the get_credential_key method."""
|
218
|
-
|
219
|
-
def test_get_credential_key(self, auth_config):
|
220
|
-
"""Test generating a unique credential key."""
|
221
|
-
handler = AuthHandler(auth_config)
|
222
|
-
key = handler.get_credential_key()
|
223
|
-
assert key.startswith("temp:adk_oauth2_")
|
224
|
-
assert "_oauth2_" in key
|
225
|
-
|
226
|
-
def test_get_credential_key_with_extras(self, auth_config):
|
227
|
-
"""Test generating a key when model_extra exists."""
|
228
|
-
# Add model_extra to test cleanup
|
229
|
-
|
230
|
-
original_key = AuthHandler(auth_config).get_credential_key()
|
231
|
-
key = AuthHandler(auth_config).get_credential_key()
|
232
|
-
|
233
|
-
auth_config.auth_scheme.model_extra["extra_field"] = "value"
|
234
|
-
auth_config.raw_auth_credential.model_extra["extra_field"] = "value"
|
235
|
-
|
236
|
-
assert original_key == key
|
237
|
-
assert "extra_field" in auth_config.auth_scheme.model_extra
|
238
|
-
assert "extra_field" in auth_config.raw_auth_credential.model_extra
|
239
|
-
|
240
|
-
|
241
|
-
class TestGenerateAuthUri:
|
242
|
-
"""Tests for the generate_auth_uri method."""
|
243
|
-
|
244
|
-
@patch("google.adk.auth.auth_handler.OAuth2Session", MockOAuth2Session)
|
245
|
-
def test_generate_auth_uri_oauth2(self, auth_config):
|
246
|
-
"""Test generating an auth URI for OAuth2."""
|
247
|
-
handler = AuthHandler(auth_config)
|
248
|
-
result = handler.generate_auth_uri()
|
249
|
-
|
250
|
-
assert result.oauth2.auth_uri.startswith(
|
251
|
-
"https://example.com/oauth2/authorize"
|
252
|
-
)
|
253
|
-
assert "client_id=mock_client_id" in result.oauth2.auth_uri
|
254
|
-
assert result.oauth2.state == "mock_state"
|
255
|
-
|
256
|
-
@patch("google.adk.auth.auth_handler.OAuth2Session", MockOAuth2Session)
|
257
|
-
def test_generate_auth_uri_openid(
|
258
|
-
self, openid_auth_scheme, oauth2_credentials
|
259
|
-
):
|
260
|
-
"""Test generating an auth URI for OpenID Connect."""
|
261
|
-
# Create a copy for the exchanged credential
|
262
|
-
exchanged = oauth2_credentials.model_copy(deep=True)
|
263
|
-
|
264
|
-
config = AuthConfig(
|
265
|
-
auth_scheme=openid_auth_scheme,
|
266
|
-
raw_auth_credential=oauth2_credentials,
|
267
|
-
exchanged_auth_credential=exchanged,
|
268
|
-
)
|
269
|
-
handler = AuthHandler(config)
|
270
|
-
result = handler.generate_auth_uri()
|
271
|
-
|
272
|
-
assert result.oauth2.auth_uri.startswith(
|
273
|
-
"https://example.com/oauth2/authorize"
|
274
|
-
)
|
275
|
-
assert "client_id=mock_client_id" in result.oauth2.auth_uri
|
276
|
-
assert result.oauth2.state == "mock_state"
|
277
|
-
|
278
|
-
|
279
|
-
class TestGenerateAuthRequest:
|
280
|
-
"""Tests for the generate_auth_request method."""
|
281
|
-
|
282
|
-
def test_non_oauth_scheme(self):
|
283
|
-
"""Test with a non-OAuth auth scheme."""
|
284
|
-
# Use a SecurityBase instance without using APIKey which has validation issues
|
285
|
-
api_key_scheme = APIKey(**{"name": "test_api_key", "in": APIKeyIn.header})
|
286
|
-
|
287
|
-
credential = AuthCredential(
|
288
|
-
auth_type=AuthCredentialTypes.API_KEY, api_key="test_api_key"
|
289
|
-
)
|
290
|
-
|
291
|
-
# Create a copy for the exchanged credential
|
292
|
-
exchanged = credential.model_copy(deep=True)
|
293
|
-
|
294
|
-
config = AuthConfig(
|
295
|
-
auth_scheme=api_key_scheme,
|
296
|
-
raw_auth_credential=credential,
|
297
|
-
exchanged_auth_credential=exchanged,
|
298
|
-
)
|
299
|
-
|
300
|
-
handler = AuthHandler(config)
|
301
|
-
result = handler.generate_auth_request()
|
302
|
-
|
303
|
-
assert result == config
|
304
|
-
|
305
|
-
def test_with_existing_auth_uri(self, auth_config_with_exchanged):
|
306
|
-
"""Test when auth_uri already exists in exchanged credential."""
|
307
|
-
handler = AuthHandler(auth_config_with_exchanged)
|
308
|
-
result = handler.generate_auth_request()
|
309
|
-
|
310
|
-
assert (
|
311
|
-
result.exchanged_auth_credential.oauth2.auth_uri
|
312
|
-
== auth_config_with_exchanged.exchanged_auth_credential.oauth2.auth_uri
|
313
|
-
)
|
314
|
-
|
315
|
-
def test_missing_raw_credential(self, oauth2_auth_scheme):
|
316
|
-
"""Test when raw_auth_credential is missing."""
|
317
|
-
|
318
|
-
config = AuthConfig(
|
319
|
-
auth_scheme=oauth2_auth_scheme,
|
320
|
-
)
|
321
|
-
handler = AuthHandler(config)
|
322
|
-
|
323
|
-
with pytest.raises(ValueError, match="requires auth_credential"):
|
324
|
-
handler.generate_auth_request()
|
325
|
-
|
326
|
-
def test_missing_oauth2_in_raw_credential(self, oauth2_auth_scheme):
|
327
|
-
"""Test when oauth2 is missing in raw_auth_credential."""
|
328
|
-
credential = AuthCredential(
|
329
|
-
auth_type=AuthCredentialTypes.API_KEY, api_key="test_api_key"
|
330
|
-
)
|
331
|
-
|
332
|
-
# Create a copy for the exchanged credential
|
333
|
-
exchanged = credential.model_copy(deep=True)
|
334
|
-
|
335
|
-
config = AuthConfig(
|
336
|
-
auth_scheme=oauth2_auth_scheme,
|
337
|
-
raw_auth_credential=credential,
|
338
|
-
exchanged_auth_credential=exchanged,
|
339
|
-
)
|
340
|
-
handler = AuthHandler(config)
|
341
|
-
|
342
|
-
with pytest.raises(ValueError, match="requires oauth2 in auth_credential"):
|
343
|
-
handler.generate_auth_request()
|
344
|
-
|
345
|
-
def test_auth_uri_in_raw_credential(
|
346
|
-
self, oauth2_auth_scheme, oauth2_credentials_with_auth_uri
|
347
|
-
):
|
348
|
-
"""Test when auth_uri exists in raw_credential."""
|
349
|
-
config = AuthConfig(
|
350
|
-
auth_scheme=oauth2_auth_scheme,
|
351
|
-
raw_auth_credential=oauth2_credentials_with_auth_uri,
|
352
|
-
exchanged_auth_credential=oauth2_credentials_with_auth_uri.model_copy(
|
353
|
-
deep=True
|
354
|
-
),
|
355
|
-
)
|
356
|
-
handler = AuthHandler(config)
|
357
|
-
result = handler.generate_auth_request()
|
358
|
-
|
359
|
-
assert (
|
360
|
-
result.exchanged_auth_credential.oauth2.auth_uri
|
361
|
-
== oauth2_credentials_with_auth_uri.oauth2.auth_uri
|
362
|
-
)
|
363
|
-
|
364
|
-
def test_missing_client_credentials(self, oauth2_auth_scheme):
|
365
|
-
"""Test when client_id or client_secret is missing."""
|
366
|
-
bad_credential = AuthCredential(
|
367
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
368
|
-
oauth2=OAuth2Auth(redirect_uri="https://example.com/callback"),
|
369
|
-
)
|
370
|
-
|
371
|
-
# Create a copy for the exchanged credential
|
372
|
-
exchanged = bad_credential.model_copy(deep=True)
|
373
|
-
|
374
|
-
config = AuthConfig(
|
375
|
-
auth_scheme=oauth2_auth_scheme,
|
376
|
-
raw_auth_credential=bad_credential,
|
377
|
-
exchanged_auth_credential=exchanged,
|
378
|
-
)
|
379
|
-
handler = AuthHandler(config)
|
380
|
-
|
381
|
-
with pytest.raises(
|
382
|
-
ValueError, match="requires both client_id and client_secret"
|
383
|
-
):
|
384
|
-
handler.generate_auth_request()
|
385
|
-
|
386
|
-
@patch("google.adk.auth.auth_handler.AuthHandler.generate_auth_uri")
|
387
|
-
def test_generate_new_auth_uri(self, mock_generate_auth_uri, auth_config):
|
388
|
-
"""Test generating a new auth URI."""
|
389
|
-
mock_credential = AuthCredential(
|
390
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
391
|
-
oauth2=OAuth2Auth(
|
392
|
-
client_id="mock_client_id",
|
393
|
-
client_secret="mock_client_secret",
|
394
|
-
redirect_uri="https://example.com/callback",
|
395
|
-
auth_uri="https://example.com/generated",
|
396
|
-
state="generated_state",
|
397
|
-
),
|
398
|
-
)
|
399
|
-
mock_generate_auth_uri.return_value = mock_credential
|
400
|
-
|
401
|
-
handler = AuthHandler(auth_config)
|
402
|
-
result = handler.generate_auth_request()
|
403
|
-
|
404
|
-
assert mock_generate_auth_uri.called
|
405
|
-
assert result.exchanged_auth_credential == mock_credential
|
406
|
-
|
407
|
-
|
408
|
-
class TestGetAuthResponse:
|
409
|
-
"""Tests for the get_auth_response method."""
|
410
|
-
|
411
|
-
def test_get_auth_response_exists(
|
412
|
-
self, auth_config, oauth2_credentials_with_auth_uri
|
413
|
-
):
|
414
|
-
"""Test retrieving an existing auth response from state."""
|
415
|
-
handler = AuthHandler(auth_config)
|
416
|
-
state = MockState()
|
417
|
-
|
418
|
-
# Store a credential in the state
|
419
|
-
credential_key = handler.get_credential_key()
|
420
|
-
state[credential_key] = oauth2_credentials_with_auth_uri
|
421
|
-
|
422
|
-
result = handler.get_auth_response(state)
|
423
|
-
assert result == oauth2_credentials_with_auth_uri
|
424
|
-
|
425
|
-
def test_get_auth_response_not_exists(self, auth_config):
|
426
|
-
"""Test retrieving a non-existent auth response from state."""
|
427
|
-
handler = AuthHandler(auth_config)
|
428
|
-
state = MockState()
|
429
|
-
|
430
|
-
result = handler.get_auth_response(state)
|
431
|
-
assert result is None
|
432
|
-
|
433
|
-
|
434
|
-
class TestParseAndStoreAuthResponse:
|
435
|
-
"""Tests for the parse_and_store_auth_response method."""
|
436
|
-
|
437
|
-
def test_non_oauth_scheme(self, auth_config_with_exchanged):
|
438
|
-
"""Test with a non-OAuth auth scheme."""
|
439
|
-
# Modify the auth scheme type to be non-OAuth
|
440
|
-
auth_config = copy.deepcopy(auth_config_with_exchanged)
|
441
|
-
auth_config.auth_scheme = APIKey(
|
442
|
-
**{"name": "test_api_key", "in": APIKeyIn.header}
|
443
|
-
)
|
444
|
-
|
445
|
-
handler = AuthHandler(auth_config)
|
446
|
-
state = MockState()
|
447
|
-
|
448
|
-
handler.parse_and_store_auth_response(state)
|
449
|
-
|
450
|
-
credential_key = handler.get_credential_key()
|
451
|
-
assert state[credential_key] == auth_config.exchanged_auth_credential
|
452
|
-
|
453
|
-
@patch("google.adk.auth.auth_handler.AuthHandler.exchange_auth_token")
|
454
|
-
def test_oauth_scheme(self, mock_exchange_token, auth_config_with_exchanged):
|
455
|
-
"""Test with an OAuth auth scheme."""
|
456
|
-
mock_exchange_token.return_value = AuthCredential(
|
457
|
-
auth_type=AuthCredentialTypes.OAUTH2,
|
458
|
-
oauth2=OAuth2Auth(token={"access_token": "exchanged_token"}),
|
459
|
-
)
|
460
|
-
|
461
|
-
handler = AuthHandler(auth_config_with_exchanged)
|
462
|
-
state = MockState()
|
463
|
-
|
464
|
-
handler.parse_and_store_auth_response(state)
|
465
|
-
|
466
|
-
credential_key = handler.get_credential_key()
|
467
|
-
assert state[credential_key] == mock_exchange_token.return_value
|
468
|
-
assert mock_exchange_token.called
|
469
|
-
|
470
|
-
|
471
|
-
class TestExchangeAuthToken:
|
472
|
-
"""Tests for the exchange_auth_token method."""
|
473
|
-
|
474
|
-
def test_token_exchange_not_supported(
|
475
|
-
self, auth_config_with_auth_code, monkeypatch
|
476
|
-
):
|
477
|
-
"""Test when token exchange is not supported."""
|
478
|
-
monkeypatch.setattr(
|
479
|
-
"google.adk.auth.auth_handler.SUPPORT_TOKEN_EXCHANGE", False
|
480
|
-
)
|
481
|
-
|
482
|
-
handler = AuthHandler(auth_config_with_auth_code)
|
483
|
-
result = handler.exchange_auth_token()
|
484
|
-
|
485
|
-
assert result == auth_config_with_auth_code.exchanged_auth_credential
|
486
|
-
|
487
|
-
def test_openid_missing_token_endpoint(
|
488
|
-
self, openid_auth_scheme, oauth2_credentials_with_auth_code
|
489
|
-
):
|
490
|
-
"""Test OpenID Connect without a token endpoint."""
|
491
|
-
# Create a scheme without token_endpoint
|
492
|
-
scheme_without_token = copy.deepcopy(openid_auth_scheme)
|
493
|
-
delattr(scheme_without_token, "token_endpoint")
|
494
|
-
|
495
|
-
config = AuthConfig(
|
496
|
-
auth_scheme=scheme_without_token,
|
497
|
-
raw_auth_credential=oauth2_credentials_with_auth_code,
|
498
|
-
exchanged_auth_credential=oauth2_credentials_with_auth_code,
|
499
|
-
)
|
500
|
-
|
501
|
-
handler = AuthHandler(config)
|
502
|
-
result = handler.exchange_auth_token()
|
503
|
-
|
504
|
-
assert result == oauth2_credentials_with_auth_code
|
505
|
-
|
506
|
-
def test_oauth2_missing_token_url(
|
507
|
-
self, oauth2_auth_scheme, oauth2_credentials_with_auth_code
|
508
|
-
):
|
509
|
-
"""Test OAuth2 without a token URL."""
|
510
|
-
# Create a scheme without tokenUrl
|
511
|
-
scheme_without_token = copy.deepcopy(oauth2_auth_scheme)
|
512
|
-
scheme_without_token.flows.authorizationCode.tokenUrl = None
|
513
|
-
|
514
|
-
config = AuthConfig(
|
515
|
-
auth_scheme=scheme_without_token,
|
516
|
-
raw_auth_credential=oauth2_credentials_with_auth_code,
|
517
|
-
exchanged_auth_credential=oauth2_credentials_with_auth_code,
|
518
|
-
)
|
519
|
-
|
520
|
-
handler = AuthHandler(config)
|
521
|
-
result = handler.exchange_auth_token()
|
522
|
-
|
523
|
-
assert result == oauth2_credentials_with_auth_code
|
524
|
-
|
525
|
-
def test_non_oauth_scheme(self, auth_config_with_auth_code):
|
526
|
-
"""Test with a non-OAuth auth scheme."""
|
527
|
-
# Modify the auth scheme type to be non-OAuth
|
528
|
-
auth_config = copy.deepcopy(auth_config_with_auth_code)
|
529
|
-
auth_config.auth_scheme = APIKey(
|
530
|
-
**{"name": "test_api_key", "in": APIKeyIn.header}
|
531
|
-
)
|
532
|
-
|
533
|
-
handler = AuthHandler(auth_config)
|
534
|
-
result = handler.exchange_auth_token()
|
535
|
-
|
536
|
-
assert result == auth_config.exchanged_auth_credential
|
537
|
-
|
538
|
-
def test_missing_credentials(self, oauth2_auth_scheme):
|
539
|
-
"""Test with missing credentials."""
|
540
|
-
empty_credential = AuthCredential(auth_type=AuthCredentialTypes.OAUTH2)
|
541
|
-
|
542
|
-
config = AuthConfig(
|
543
|
-
auth_scheme=oauth2_auth_scheme,
|
544
|
-
exchanged_auth_credential=empty_credential,
|
545
|
-
)
|
546
|
-
|
547
|
-
handler = AuthHandler(config)
|
548
|
-
result = handler.exchange_auth_token()
|
549
|
-
|
550
|
-
assert result == empty_credential
|
551
|
-
|
552
|
-
def test_credentials_with_token(
|
553
|
-
self, auth_config, oauth2_credentials_with_token
|
554
|
-
):
|
555
|
-
"""Test when credentials already have a token."""
|
556
|
-
config = AuthConfig(
|
557
|
-
auth_scheme=auth_config.auth_scheme,
|
558
|
-
raw_auth_credential=auth_config.raw_auth_credential,
|
559
|
-
exchanged_auth_credential=oauth2_credentials_with_token,
|
560
|
-
)
|
561
|
-
|
562
|
-
handler = AuthHandler(config)
|
563
|
-
result = handler.exchange_auth_token()
|
564
|
-
|
565
|
-
assert result == oauth2_credentials_with_token
|
566
|
-
|
567
|
-
@patch("google.adk.auth.auth_handler.OAuth2Session", MockOAuth2Session)
|
568
|
-
def test_successful_token_exchange(self, auth_config_with_auth_code):
|
569
|
-
"""Test a successful token exchange."""
|
570
|
-
handler = AuthHandler(auth_config_with_auth_code)
|
571
|
-
result = handler.exchange_auth_token()
|
572
|
-
|
573
|
-
assert result.oauth2.token["access_token"] == "mock_access_token"
|
574
|
-
assert result.oauth2.token["refresh_token"] == "mock_refresh_token"
|
575
|
-
assert result.auth_type == AuthCredentialTypes.OAUTH2
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# Copyright 2025 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
import os
|
16
|
-
|
17
|
-
from pytest import fixture
|
18
|
-
from pytest import FixtureRequest
|
19
|
-
from pytest import hookimpl
|
20
|
-
from pytest import Metafunc
|
21
|
-
|
22
|
-
_ENV_VARS = {
|
23
|
-
'GOOGLE_API_KEY': 'fake_google_api_key',
|
24
|
-
'GOOGLE_CLOUD_PROJECT': 'fake_google_cloud_project',
|
25
|
-
'GOOGLE_CLOUD_LOCATION': 'fake_google_cloud_location',
|
26
|
-
}
|
27
|
-
|
28
|
-
ENV_SETUPS = {
|
29
|
-
'GOOGLE_AI': {
|
30
|
-
'GOOGLE_GENAI_USE_VERTEXAI': '0',
|
31
|
-
**_ENV_VARS,
|
32
|
-
},
|
33
|
-
'VERTEX': {
|
34
|
-
'GOOGLE_GENAI_USE_VERTEXAI': '1',
|
35
|
-
**_ENV_VARS,
|
36
|
-
},
|
37
|
-
}
|
38
|
-
|
39
|
-
|
40
|
-
@fixture(autouse=True)
|
41
|
-
def env_variables(request: FixtureRequest):
|
42
|
-
# Set up the environment
|
43
|
-
env_name: str = request.param
|
44
|
-
envs = ENV_SETUPS[env_name]
|
45
|
-
original_env = {key: os.environ.get(key) for key in envs}
|
46
|
-
os.environ.update(envs)
|
47
|
-
|
48
|
-
yield # Run the test
|
49
|
-
|
50
|
-
# Restore the environment
|
51
|
-
for key in envs:
|
52
|
-
if (original_val := original_env.get(key)) is None:
|
53
|
-
os.environ.pop(key, None)
|
54
|
-
else:
|
55
|
-
os.environ[key] = original_val
|
56
|
-
|
57
|
-
|
58
|
-
@hookimpl(tryfirst=True)
|
59
|
-
def pytest_generate_tests(metafunc: Metafunc):
|
60
|
-
"""Generate test cases for each environment setup."""
|
61
|
-
if env_variables.__name__ in metafunc.fixturenames:
|
62
|
-
if not _is_explicitly_marked(env_variables.__name__, metafunc):
|
63
|
-
metafunc.parametrize(
|
64
|
-
env_variables.__name__, ENV_SETUPS.keys(), indirect=True
|
65
|
-
)
|
66
|
-
|
67
|
-
|
68
|
-
def _is_explicitly_marked(mark_name: str, metafunc: Metafunc) -> bool:
|
69
|
-
if hasattr(metafunc.function, 'pytestmark'):
|
70
|
-
for mark in metafunc.function.pytestmark:
|
71
|
-
if mark.name == 'parametrize' and mark.args[0] == mark_name:
|
72
|
-
return True
|
73
|
-
return False
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# Copyright 2025 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|