google-adk 0.0.3__py3-none-any.whl → 0.0.5__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.
Files changed (185) hide show
  1. google/adk/agents/run_config.py +4 -0
  2. google/adk/auth/auth_preprocessor.py +19 -16
  3. google/adk/cli/browser/index.html +1 -1
  4. google/adk/cli/browser/{main-SY2WYYGV.js → main-SLIAU2JL.js} +46 -30
  5. google/adk/cli/cli.py +8 -8
  6. google/adk/cli/cli_deploy.py +2 -4
  7. google/adk/cli/cli_tools_click.py +6 -6
  8. google/adk/flows/llm_flows/base_llm_flow.py +1 -1
  9. google/adk/flows/llm_flows/contents.py +21 -1
  10. google/adk/flows/llm_flows/functions.py +3 -1
  11. google/adk/models/google_llm.py +0 -1
  12. google/adk/runners.py +13 -2
  13. google/adk/version.py +1 -1
  14. {google_adk-0.0.3.dist-info → google_adk-0.0.5.dist-info}/METADATA +4 -2
  15. google_adk-0.0.5.dist-info/RECORD +175 -0
  16. {google_adk-0.0.3.dist-info → google_adk-0.0.5.dist-info}/WHEEL +1 -1
  17. google_adk-0.0.5.dist-info/licenses/LICENSE +202 -0
  18. google/adk/._version.py +0 -0
  19. google/adk/docs/Makefile +0 -20
  20. google/adk/docs/build/doctrees/google-adk.doctree +0 -0
  21. google/adk/docs/build/html/_sources/google-adk.rst.txt +0 -98
  22. google/adk/docs/build/html/_sources/index.rst.txt +0 -7
  23. google/adk/docs/build/html/_static/autodoc_pydantic.css +0 -27
  24. google/adk/docs/build/html/_static/basic.css +0 -925
  25. google/adk/docs/build/html/_static/debug.css +0 -85
  26. google/adk/docs/build/html/_static/doctools.js +0 -156
  27. google/adk/docs/build/html/_static/documentation_options.js +0 -29
  28. google/adk/docs/build/html/_static/file.png +0 -0
  29. google/adk/docs/build/html/_static/language_data.js +0 -199
  30. google/adk/docs/build/html/_static/minus.png +0 -0
  31. google/adk/docs/build/html/_static/plus.png +0 -0
  32. google/adk/docs/build/html/_static/pygments.css +0 -274
  33. google/adk/docs/build/html/_static/scripts/furo-extensions.js +0 -16
  34. google/adk/docs/build/html/_static/scripts/furo.js +0 -19
  35. google/adk/docs/build/html/_static/scripts/furo.js.LICENSE.txt +0 -7
  36. google/adk/docs/build/html/_static/scripts/furo.js.map +0 -1
  37. google/adk/docs/build/html/_static/searchtools.js +0 -620
  38. google/adk/docs/build/html/_static/skeleton.css +0 -312
  39. google/adk/docs/build/html/_static/sphinx_highlight.js +0 -170
  40. google/adk/docs/build/html/_static/styles/furo-extensions.css +0 -18
  41. google/adk/docs/build/html/_static/styles/furo-extensions.css.map +0 -1
  42. google/adk/docs/build/html/_static/styles/furo.css +0 -18
  43. google/adk/docs/build/html/_static/styles/furo.css.map +0 -1
  44. google/adk/docs/build/html/genindex.html +0 -861
  45. google/adk/docs/build/html/google-adk.html +0 -5461
  46. google/adk/docs/build/html/index.html +0 -567
  47. google/adk/docs/build/html/objects.inv +0 -0
  48. google/adk/docs/build/html/py-modindex.html +0 -373
  49. google/adk/docs/build/html/search.html +0 -333
  50. google/adk/docs/build/html/searchindex.js +0 -17
  51. google/adk/docs/source/conf.py +0 -133
  52. google/adk/docs/source/google-adk.rst +0 -98
  53. google/adk/docs/source/index.rst +0 -7
  54. google/adk/tests/__init__.py +0 -14
  55. google/adk/tests/integration/.env.example +0 -10
  56. google/adk/tests/integration/__init__.py +0 -18
  57. google/adk/tests/integration/conftest.py +0 -119
  58. google/adk/tests/integration/fixture/__init__.py +0 -14
  59. google/adk/tests/integration/fixture/agent_with_config/__init__.py +0 -15
  60. google/adk/tests/integration/fixture/agent_with_config/agent.py +0 -88
  61. google/adk/tests/integration/fixture/callback_agent/__init__.py +0 -15
  62. google/adk/tests/integration/fixture/callback_agent/agent.py +0 -105
  63. google/adk/tests/integration/fixture/context_update_test/OWNERS +0 -1
  64. google/adk/tests/integration/fixture/context_update_test/__init__.py +0 -15
  65. google/adk/tests/integration/fixture/context_update_test/agent.py +0 -43
  66. google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +0 -582
  67. google/adk/tests/integration/fixture/context_variable_agent/__init__.py +0 -15
  68. google/adk/tests/integration/fixture/context_variable_agent/agent.py +0 -115
  69. google/adk/tests/integration/fixture/customer_support_ma/__init__.py +0 -15
  70. google/adk/tests/integration/fixture/customer_support_ma/agent.py +0 -172
  71. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +0 -15
  72. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +0 -338
  73. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +0 -69
  74. google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +0 -6
  75. google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +0 -15
  76. google/adk/tests/integration/fixture/flow_complex_spark/agent.py +0 -182
  77. google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +0 -190
  78. google/adk/tests/integration/fixture/hello_world_agent/__init__.py +0 -15
  79. google/adk/tests/integration/fixture/hello_world_agent/agent.py +0 -95
  80. google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +0 -24
  81. google/adk/tests/integration/fixture/hello_world_agent/test_config.json +0 -6
  82. google/adk/tests/integration/fixture/home_automation_agent/__init__.py +0 -15
  83. google/adk/tests/integration/fixture/home_automation_agent/agent.py +0 -304
  84. google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +0 -5
  85. google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +0 -5
  86. google/adk/tests/integration/fixture/home_automation_agent/test_config.json +0 -5
  87. google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +0 -18
  88. google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +0 -17
  89. google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +0 -6
  90. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +0 -18
  91. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +0 -17
  92. google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +0 -5
  93. google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +0 -5
  94. google/adk/tests/integration/fixture/tool_agent/__init__.py +0 -15
  95. google/adk/tests/integration/fixture/tool_agent/agent.py +0 -218
  96. google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
  97. google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +0 -15
  98. google/adk/tests/integration/fixture/trip_planner_agent/agent.py +0 -110
  99. google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +0 -13
  100. google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +0 -5
  101. google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +0 -13
  102. google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +0 -5
  103. google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +0 -7
  104. google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +0 -19
  105. google/adk/tests/integration/models/__init__.py +0 -14
  106. google/adk/tests/integration/models/test_google_llm.py +0 -65
  107. google/adk/tests/integration/test_callback.py +0 -70
  108. google/adk/tests/integration/test_context_variable.py +0 -67
  109. google/adk/tests/integration/test_evalute_agent_in_fixture.py +0 -76
  110. google/adk/tests/integration/test_multi_agent.py +0 -28
  111. google/adk/tests/integration/test_multi_turn.py +0 -42
  112. google/adk/tests/integration/test_single_agent.py +0 -23
  113. google/adk/tests/integration/test_sub_agent.py +0 -26
  114. google/adk/tests/integration/test_system_instruction.py +0 -177
  115. google/adk/tests/integration/test_tools.py +0 -287
  116. google/adk/tests/integration/test_with_test_file.py +0 -34
  117. google/adk/tests/integration/tools/__init__.py +0 -14
  118. google/adk/tests/integration/utils/__init__.py +0 -16
  119. google/adk/tests/integration/utils/asserts.py +0 -75
  120. google/adk/tests/integration/utils/test_runner.py +0 -97
  121. google/adk/tests/unittests/__init__.py +0 -14
  122. google/adk/tests/unittests/agents/__init__.py +0 -14
  123. google/adk/tests/unittests/agents/test_base_agent.py +0 -407
  124. google/adk/tests/unittests/agents/test_langgraph_agent.py +0 -191
  125. google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +0 -138
  126. google/adk/tests/unittests/agents/test_llm_agent_fields.py +0 -231
  127. google/adk/tests/unittests/agents/test_loop_agent.py +0 -136
  128. google/adk/tests/unittests/agents/test_parallel_agent.py +0 -92
  129. google/adk/tests/unittests/agents/test_sequential_agent.py +0 -114
  130. google/adk/tests/unittests/artifacts/__init__.py +0 -14
  131. google/adk/tests/unittests/artifacts/test_artifact_service.py +0 -276
  132. google/adk/tests/unittests/auth/test_auth_handler.py +0 -575
  133. google/adk/tests/unittests/conftest.py +0 -73
  134. google/adk/tests/unittests/fast_api/__init__.py +0 -14
  135. google/adk/tests/unittests/fast_api/test_fast_api.py +0 -269
  136. google/adk/tests/unittests/flows/__init__.py +0 -14
  137. google/adk/tests/unittests/flows/llm_flows/__init__.py +0 -14
  138. google/adk/tests/unittests/flows/llm_flows/_test_examples.py +0 -142
  139. google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +0 -311
  140. google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +0 -244
  141. google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +0 -346
  142. google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +0 -93
  143. google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +0 -258
  144. google/adk/tests/unittests/flows/llm_flows/test_identity.py +0 -66
  145. google/adk/tests/unittests/flows/llm_flows/test_instructions.py +0 -164
  146. google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +0 -142
  147. google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +0 -46
  148. google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +0 -269
  149. google/adk/tests/unittests/models/__init__.py +0 -14
  150. google/adk/tests/unittests/models/test_google_llm.py +0 -224
  151. google/adk/tests/unittests/models/test_litellm.py +0 -804
  152. google/adk/tests/unittests/models/test_models.py +0 -60
  153. google/adk/tests/unittests/sessions/__init__.py +0 -14
  154. google/adk/tests/unittests/sessions/test_session_service.py +0 -227
  155. google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +0 -246
  156. google/adk/tests/unittests/streaming/__init__.py +0 -14
  157. google/adk/tests/unittests/streaming/test_streaming.py +0 -50
  158. google/adk/tests/unittests/tools/__init__.py +0 -14
  159. google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +0 -499
  160. google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +0 -204
  161. google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +0 -600
  162. google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +0 -630
  163. google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +0 -345
  164. google/adk/tests/unittests/tools/google_api_tool/__init__.py +0 -13
  165. google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +0 -657
  166. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +0 -145
  167. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +0 -68
  168. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +0 -153
  169. google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +0 -196
  170. google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +0 -573
  171. google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +0 -436
  172. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +0 -1367
  173. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +0 -628
  174. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +0 -139
  175. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +0 -406
  176. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +0 -966
  177. google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +0 -201
  178. google/adk/tests/unittests/tools/retrieval/__init__.py +0 -14
  179. google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +0 -147
  180. google/adk/tests/unittests/tools/test_agent_tool.py +0 -167
  181. google/adk/tests/unittests/tools/test_base_tool.py +0 -141
  182. google/adk/tests/unittests/tools/test_build_function_declaration.py +0 -277
  183. google/adk/tests/unittests/utils.py +0 -304
  184. google_adk-0.0.3.dist-info/RECORD +0 -340
  185. {google_adk-0.0.3.dist-info → google_adk-0.0.5.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
-