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,499 +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 base64
|
16
|
-
import json
|
17
|
-
from unittest.mock import MagicMock, patch
|
18
|
-
from google.adk.tools.apihub_tool.clients.apihub_client import APIHubClient
|
19
|
-
import pytest
|
20
|
-
from requests.exceptions import HTTPError
|
21
|
-
|
22
|
-
# Mock data for API responses
|
23
|
-
MOCK_API_LIST = {
|
24
|
-
"apis": [
|
25
|
-
{"name": "projects/test-project/locations/us-central1/apis/api1"},
|
26
|
-
{"name": "projects/test-project/locations/us-central1/apis/api2"},
|
27
|
-
]
|
28
|
-
}
|
29
|
-
MOCK_API_DETAIL = {
|
30
|
-
"name": "projects/test-project/locations/us-central1/apis/api1",
|
31
|
-
"versions": [
|
32
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
33
|
-
],
|
34
|
-
}
|
35
|
-
MOCK_API_VERSION = {
|
36
|
-
"name": "projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
37
|
-
"specs": [
|
38
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1"
|
39
|
-
],
|
40
|
-
}
|
41
|
-
MOCK_SPEC_CONTENT = {"contents": base64.b64encode(b"spec content").decode()}
|
42
|
-
|
43
|
-
|
44
|
-
# Test cases
|
45
|
-
class TestAPIHubClient:
|
46
|
-
|
47
|
-
@pytest.fixture
|
48
|
-
def client(self):
|
49
|
-
return APIHubClient(access_token="mocked_token")
|
50
|
-
|
51
|
-
@pytest.fixture
|
52
|
-
def service_account_config(self):
|
53
|
-
return json.dumps({
|
54
|
-
"type": "service_account",
|
55
|
-
"project_id": "test",
|
56
|
-
"token_uri": "test.com",
|
57
|
-
"client_email": "test@example.com",
|
58
|
-
"private_key": "1234",
|
59
|
-
})
|
60
|
-
|
61
|
-
@patch("requests.get")
|
62
|
-
def test_list_apis(self, mock_get, client):
|
63
|
-
mock_get.return_value.json.return_value = MOCK_API_LIST
|
64
|
-
mock_get.return_value.status_code = 200
|
65
|
-
|
66
|
-
apis = client.list_apis("test-project", "us-central1")
|
67
|
-
assert apis == MOCK_API_LIST["apis"]
|
68
|
-
mock_get.assert_called_once_with(
|
69
|
-
"https://apihub.googleapis.com/v1/projects/test-project/locations/us-central1/apis",
|
70
|
-
headers={
|
71
|
-
"accept": "application/json, text/plain, */*",
|
72
|
-
"Authorization": "Bearer mocked_token",
|
73
|
-
},
|
74
|
-
)
|
75
|
-
|
76
|
-
@patch("requests.get")
|
77
|
-
def test_list_apis_empty(self, mock_get, client):
|
78
|
-
mock_get.return_value.json.return_value = {"apis": []}
|
79
|
-
mock_get.return_value.status_code = 200
|
80
|
-
|
81
|
-
apis = client.list_apis("test-project", "us-central1")
|
82
|
-
assert apis == []
|
83
|
-
|
84
|
-
@patch("requests.get")
|
85
|
-
def test_list_apis_error(self, mock_get, client):
|
86
|
-
mock_get.return_value.raise_for_status.side_effect = HTTPError
|
87
|
-
|
88
|
-
with pytest.raises(HTTPError):
|
89
|
-
client.list_apis("test-project", "us-central1")
|
90
|
-
|
91
|
-
@patch("requests.get")
|
92
|
-
def test_get_api(self, mock_get, client):
|
93
|
-
mock_get.return_value.json.return_value = MOCK_API_DETAIL
|
94
|
-
mock_get.return_value.status_code = 200
|
95
|
-
api = client.get_api(
|
96
|
-
"projects/test-project/locations/us-central1/apis/api1"
|
97
|
-
)
|
98
|
-
assert api == MOCK_API_DETAIL
|
99
|
-
mock_get.assert_called_once_with(
|
100
|
-
"https://apihub.googleapis.com/v1/projects/test-project/locations/us-central1/apis/api1",
|
101
|
-
headers={
|
102
|
-
"accept": "application/json, text/plain, */*",
|
103
|
-
"Authorization": "Bearer mocked_token",
|
104
|
-
},
|
105
|
-
)
|
106
|
-
|
107
|
-
@patch("requests.get")
|
108
|
-
def test_get_api_error(self, mock_get, client):
|
109
|
-
mock_get.return_value.raise_for_status.side_effect = HTTPError
|
110
|
-
with pytest.raises(HTTPError):
|
111
|
-
client.get_api("projects/test-project/locations/us-central1/apis/api1")
|
112
|
-
|
113
|
-
@patch("requests.get")
|
114
|
-
def test_get_api_version(self, mock_get, client):
|
115
|
-
mock_get.return_value.json.return_value = MOCK_API_VERSION
|
116
|
-
mock_get.return_value.status_code = 200
|
117
|
-
api_version = client.get_api_version(
|
118
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
119
|
-
)
|
120
|
-
assert api_version == MOCK_API_VERSION
|
121
|
-
mock_get.assert_called_once_with(
|
122
|
-
"https://apihub.googleapis.com/v1/projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
123
|
-
headers={
|
124
|
-
"accept": "application/json, text/plain, */*",
|
125
|
-
"Authorization": "Bearer mocked_token",
|
126
|
-
},
|
127
|
-
)
|
128
|
-
|
129
|
-
@patch("requests.get")
|
130
|
-
def test_get_api_version_error(self, mock_get, client):
|
131
|
-
mock_get.return_value.raise_for_status.side_effect = HTTPError
|
132
|
-
with pytest.raises(HTTPError):
|
133
|
-
client.get_api_version(
|
134
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
135
|
-
)
|
136
|
-
|
137
|
-
@patch("requests.get")
|
138
|
-
def test_get_spec_content(self, mock_get, client):
|
139
|
-
mock_get.return_value.json.return_value = MOCK_SPEC_CONTENT
|
140
|
-
mock_get.return_value.status_code = 200
|
141
|
-
spec_content = client.get_spec_content(
|
142
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1"
|
143
|
-
)
|
144
|
-
assert spec_content == "spec content"
|
145
|
-
mock_get.assert_called_once_with(
|
146
|
-
"https://apihub.googleapis.com/v1/projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1:contents",
|
147
|
-
headers={
|
148
|
-
"accept": "application/json, text/plain, */*",
|
149
|
-
"Authorization": "Bearer mocked_token",
|
150
|
-
},
|
151
|
-
)
|
152
|
-
|
153
|
-
@patch("requests.get")
|
154
|
-
def test_get_spec_content_empty(self, mock_get, client):
|
155
|
-
mock_get.return_value.json.return_value = {"contents": ""}
|
156
|
-
mock_get.return_value.status_code = 200
|
157
|
-
spec_content = client.get_spec_content(
|
158
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1"
|
159
|
-
)
|
160
|
-
assert spec_content == ""
|
161
|
-
|
162
|
-
@patch("requests.get")
|
163
|
-
def test_get_spec_content_error(self, mock_get, client):
|
164
|
-
mock_get.return_value.raise_for_status.side_effect = HTTPError
|
165
|
-
with pytest.raises(HTTPError):
|
166
|
-
client.get_spec_content(
|
167
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1"
|
168
|
-
)
|
169
|
-
|
170
|
-
@pytest.mark.parametrize(
|
171
|
-
"url_or_path, expected",
|
172
|
-
[
|
173
|
-
(
|
174
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
175
|
-
(
|
176
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
177
|
-
None,
|
178
|
-
None,
|
179
|
-
),
|
180
|
-
),
|
181
|
-
(
|
182
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
183
|
-
(
|
184
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
185
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
186
|
-
None,
|
187
|
-
),
|
188
|
-
),
|
189
|
-
(
|
190
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1",
|
191
|
-
(
|
192
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
193
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
194
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1",
|
195
|
-
),
|
196
|
-
),
|
197
|
-
(
|
198
|
-
"https://console.cloud.google.com/apigee/api-hub/projects/test-project/locations/us-central1/apis/api1/versions/v1?project=test-project",
|
199
|
-
(
|
200
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
201
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
202
|
-
None,
|
203
|
-
),
|
204
|
-
),
|
205
|
-
(
|
206
|
-
"https://console.cloud.google.com/apigee/api-hub/projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1?project=test-project",
|
207
|
-
(
|
208
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
209
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
210
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1",
|
211
|
-
),
|
212
|
-
),
|
213
|
-
(
|
214
|
-
"/projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
215
|
-
(
|
216
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
217
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1",
|
218
|
-
None,
|
219
|
-
),
|
220
|
-
),
|
221
|
-
( # Added trailing slashes
|
222
|
-
"projects/test-project/locations/us-central1/apis/api1/",
|
223
|
-
(
|
224
|
-
"projects/test-project/locations/us-central1/apis/api1",
|
225
|
-
None,
|
226
|
-
None,
|
227
|
-
),
|
228
|
-
),
|
229
|
-
( # case location name
|
230
|
-
"projects/test-project/locations/LOCATION/apis/api1/",
|
231
|
-
(
|
232
|
-
"projects/test-project/locations/LOCATION/apis/api1",
|
233
|
-
None,
|
234
|
-
None,
|
235
|
-
),
|
236
|
-
),
|
237
|
-
(
|
238
|
-
"projects/p1/locations/l1/apis/a1/versions/v1/specs/s1",
|
239
|
-
(
|
240
|
-
"projects/p1/locations/l1/apis/a1",
|
241
|
-
"projects/p1/locations/l1/apis/a1/versions/v1",
|
242
|
-
"projects/p1/locations/l1/apis/a1/versions/v1/specs/s1",
|
243
|
-
),
|
244
|
-
),
|
245
|
-
],
|
246
|
-
)
|
247
|
-
def test_extract_resource_name(self, client, url_or_path, expected):
|
248
|
-
result = client._extract_resource_name(url_or_path)
|
249
|
-
assert result == expected
|
250
|
-
|
251
|
-
@pytest.mark.parametrize(
|
252
|
-
"url_or_path, expected_error_message",
|
253
|
-
[
|
254
|
-
(
|
255
|
-
"invalid-path",
|
256
|
-
"Project ID not found in URL or path in APIHubClient.",
|
257
|
-
),
|
258
|
-
(
|
259
|
-
"projects/test-project",
|
260
|
-
"Location not found in URL or path in APIHubClient.",
|
261
|
-
),
|
262
|
-
(
|
263
|
-
"projects/test-project/locations/us-central1",
|
264
|
-
"API id not found in URL or path in APIHubClient.",
|
265
|
-
),
|
266
|
-
],
|
267
|
-
)
|
268
|
-
def test_extract_resource_name_invalid(
|
269
|
-
self, client, url_or_path, expected_error_message
|
270
|
-
):
|
271
|
-
with pytest.raises(ValueError, match=expected_error_message):
|
272
|
-
client._extract_resource_name(url_or_path)
|
273
|
-
|
274
|
-
@patch(
|
275
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.default_service_credential"
|
276
|
-
)
|
277
|
-
@patch(
|
278
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.service_account.Credentials.from_service_account_info"
|
279
|
-
)
|
280
|
-
def test_get_access_token_use_default_credential(
|
281
|
-
self,
|
282
|
-
mock_from_service_account_info,
|
283
|
-
mock_default_service_credential,
|
284
|
-
):
|
285
|
-
mock_credential = MagicMock()
|
286
|
-
mock_credential.token = "default_token"
|
287
|
-
mock_default_service_credential.return_value = (
|
288
|
-
mock_credential,
|
289
|
-
"project_id",
|
290
|
-
)
|
291
|
-
mock_config_credential = MagicMock()
|
292
|
-
mock_config_credential.token = "config_token"
|
293
|
-
mock_from_service_account_info.return_value = mock_config_credential
|
294
|
-
|
295
|
-
client = APIHubClient()
|
296
|
-
token = client._get_access_token()
|
297
|
-
assert token == "default_token"
|
298
|
-
mock_credential.refresh.assert_called_once()
|
299
|
-
assert client.credential_cache == mock_credential
|
300
|
-
|
301
|
-
@patch(
|
302
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.default_service_credential"
|
303
|
-
)
|
304
|
-
@patch(
|
305
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.service_account.Credentials.from_service_account_info"
|
306
|
-
)
|
307
|
-
def test_get_access_token_use_configured_service_account(
|
308
|
-
self,
|
309
|
-
mock_from_service_account_info,
|
310
|
-
mock_default_service_credential,
|
311
|
-
service_account_config,
|
312
|
-
):
|
313
|
-
mock_credential = MagicMock()
|
314
|
-
mock_credential.token = "default_token"
|
315
|
-
mock_default_service_credential.return_value = (
|
316
|
-
mock_credential,
|
317
|
-
"project_id",
|
318
|
-
)
|
319
|
-
mock_config_credential = MagicMock()
|
320
|
-
mock_config_credential.token = "config_token"
|
321
|
-
mock_from_service_account_info.return_value = mock_config_credential
|
322
|
-
|
323
|
-
client = APIHubClient(service_account_json=service_account_config)
|
324
|
-
token = client._get_access_token()
|
325
|
-
|
326
|
-
assert token == "config_token"
|
327
|
-
mock_from_service_account_info.assert_called_once_with(
|
328
|
-
json.loads(service_account_config),
|
329
|
-
scopes=["https://www.googleapis.com/auth/cloud-platform"],
|
330
|
-
)
|
331
|
-
mock_config_credential.refresh.assert_called_once()
|
332
|
-
assert client.credential_cache == mock_config_credential
|
333
|
-
|
334
|
-
@patch(
|
335
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.default_service_credential"
|
336
|
-
)
|
337
|
-
def test_get_access_token_not_expired_use_cached_token(
|
338
|
-
self, mock_default_credential
|
339
|
-
):
|
340
|
-
mock_credentials = MagicMock()
|
341
|
-
mock_credentials.token = "default_service_account_token"
|
342
|
-
mock_default_credential.return_value = (mock_credentials, "")
|
343
|
-
|
344
|
-
client = APIHubClient()
|
345
|
-
# Call #1: Setup cache
|
346
|
-
token = client._get_access_token()
|
347
|
-
assert token == "default_service_account_token"
|
348
|
-
mock_default_credential.assert_called_once()
|
349
|
-
|
350
|
-
# Call #2: Reuse cache
|
351
|
-
mock_credentials.reset_mock()
|
352
|
-
mock_credentials.expired = False
|
353
|
-
token = client._get_access_token()
|
354
|
-
assert token == "default_service_account_token"
|
355
|
-
mock_credentials.refresh.assert_not_called()
|
356
|
-
|
357
|
-
@patch(
|
358
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.default_service_credential"
|
359
|
-
)
|
360
|
-
def test_get_access_token_expired_refresh(self, mock_default_credential):
|
361
|
-
mock_credentials = MagicMock()
|
362
|
-
mock_credentials.token = "default_service_account_token"
|
363
|
-
mock_default_credential.return_value = (mock_credentials, "")
|
364
|
-
client = APIHubClient()
|
365
|
-
|
366
|
-
# Call #1: Setup cache
|
367
|
-
token = client._get_access_token()
|
368
|
-
assert token == "default_service_account_token"
|
369
|
-
mock_default_credential.assert_called_once()
|
370
|
-
|
371
|
-
# Call #2: Cache expired
|
372
|
-
mock_credentials.reset_mock()
|
373
|
-
mock_credentials.expired = True
|
374
|
-
token = client._get_access_token()
|
375
|
-
mock_credentials.refresh.assert_called_once()
|
376
|
-
assert token == "default_service_account_token"
|
377
|
-
|
378
|
-
@patch(
|
379
|
-
"google.adk.tools.apihub_tool.clients.apihub_client.default_service_credential"
|
380
|
-
)
|
381
|
-
def test_get_access_token_no_credentials(
|
382
|
-
self, mock_default_service_credential
|
383
|
-
):
|
384
|
-
mock_default_service_credential.return_value = (None, None)
|
385
|
-
with pytest.raises(
|
386
|
-
ValueError,
|
387
|
-
match=(
|
388
|
-
"Please provide a service account or an access token to API Hub"
|
389
|
-
" client."
|
390
|
-
),
|
391
|
-
):
|
392
|
-
# no service account client
|
393
|
-
APIHubClient()._get_access_token()
|
394
|
-
|
395
|
-
@patch("requests.get")
|
396
|
-
def test_get_spec_content_api_level(self, mock_get, client):
|
397
|
-
mock_get.side_effect = [
|
398
|
-
MagicMock(status_code=200, json=lambda: MOCK_API_DETAIL), # For get_api
|
399
|
-
MagicMock(
|
400
|
-
status_code=200, json=lambda: MOCK_API_VERSION
|
401
|
-
), # For get_api_version
|
402
|
-
MagicMock(
|
403
|
-
status_code=200, json=lambda: MOCK_SPEC_CONTENT
|
404
|
-
), # For get_spec_content
|
405
|
-
]
|
406
|
-
|
407
|
-
content = client.get_spec_content(
|
408
|
-
"projects/test-project/locations/us-central1/apis/api1"
|
409
|
-
)
|
410
|
-
assert content == "spec content"
|
411
|
-
# Check calls - get_api, get_api_version, then get_spec_content
|
412
|
-
assert mock_get.call_count == 3
|
413
|
-
|
414
|
-
@patch("requests.get")
|
415
|
-
def test_get_spec_content_version_level(self, mock_get, client):
|
416
|
-
mock_get.side_effect = [
|
417
|
-
MagicMock(
|
418
|
-
status_code=200, json=lambda: MOCK_API_VERSION
|
419
|
-
), # For get_api_version
|
420
|
-
MagicMock(
|
421
|
-
status_code=200, json=lambda: MOCK_SPEC_CONTENT
|
422
|
-
), # For get_spec_content
|
423
|
-
]
|
424
|
-
|
425
|
-
content = client.get_spec_content(
|
426
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
427
|
-
)
|
428
|
-
assert content == "spec content"
|
429
|
-
assert mock_get.call_count == 2 # get_api_version and get_spec_content
|
430
|
-
|
431
|
-
@patch("requests.get")
|
432
|
-
def test_get_spec_content_spec_level(self, mock_get, client):
|
433
|
-
mock_get.return_value.json.return_value = MOCK_SPEC_CONTENT
|
434
|
-
mock_get.return_value.status_code = 200
|
435
|
-
|
436
|
-
content = client.get_spec_content(
|
437
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1/specs/spec1"
|
438
|
-
)
|
439
|
-
assert content == "spec content"
|
440
|
-
mock_get.assert_called_once() # Only get_spec_content should be called
|
441
|
-
|
442
|
-
@patch("requests.get")
|
443
|
-
def test_get_spec_content_no_versions(self, mock_get, client):
|
444
|
-
mock_get.return_value.json.return_value = {
|
445
|
-
"name": "projects/test-project/locations/us-central1/apis/api1",
|
446
|
-
"versions": [],
|
447
|
-
} # No versions
|
448
|
-
mock_get.return_value.status_code = 200
|
449
|
-
with pytest.raises(
|
450
|
-
ValueError,
|
451
|
-
match=(
|
452
|
-
"No versions found in API Hub resource:"
|
453
|
-
" projects/test-project/locations/us-central1/apis/api1"
|
454
|
-
),
|
455
|
-
):
|
456
|
-
client.get_spec_content(
|
457
|
-
"projects/test-project/locations/us-central1/apis/api1"
|
458
|
-
)
|
459
|
-
|
460
|
-
@patch("requests.get")
|
461
|
-
def test_get_spec_content_no_specs(self, mock_get, client):
|
462
|
-
mock_get.side_effect = [
|
463
|
-
MagicMock(status_code=200, json=lambda: MOCK_API_DETAIL),
|
464
|
-
MagicMock(
|
465
|
-
status_code=200,
|
466
|
-
json=lambda: {
|
467
|
-
"name": (
|
468
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
469
|
-
),
|
470
|
-
"specs": [],
|
471
|
-
},
|
472
|
-
), # No specs
|
473
|
-
]
|
474
|
-
|
475
|
-
with pytest.raises(
|
476
|
-
ValueError,
|
477
|
-
match=(
|
478
|
-
"No specs found in API Hub version:"
|
479
|
-
" projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
480
|
-
),
|
481
|
-
):
|
482
|
-
client.get_spec_content(
|
483
|
-
"projects/test-project/locations/us-central1/apis/api1/versions/v1"
|
484
|
-
)
|
485
|
-
|
486
|
-
@patch("requests.get")
|
487
|
-
def test_get_spec_content_invalid_path(self, mock_get, client):
|
488
|
-
with pytest.raises(
|
489
|
-
ValueError,
|
490
|
-
match=(
|
491
|
-
"Project ID not found in URL or path in APIHubClient. Input"
|
492
|
-
" path is 'invalid-path'."
|
493
|
-
),
|
494
|
-
):
|
495
|
-
client.get_spec_content("invalid-path")
|
496
|
-
|
497
|
-
|
498
|
-
if __name__ == "__main__":
|
499
|
-
pytest.main([__file__])
|
@@ -1,204 +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
|
-
from unittest.mock import MagicMock
|
16
|
-
|
17
|
-
from google.adk.auth.auth_credential import AuthCredential
|
18
|
-
from google.adk.auth.auth_schemes import AuthScheme
|
19
|
-
from google.adk.tools.apihub_tool.apihub_toolset import APIHubToolset
|
20
|
-
from google.adk.tools.apihub_tool.clients.apihub_client import BaseAPIHubClient
|
21
|
-
import pytest
|
22
|
-
import yaml
|
23
|
-
|
24
|
-
|
25
|
-
class MockAPIHubClient(BaseAPIHubClient):
|
26
|
-
|
27
|
-
def get_spec_content(self, apihub_resource_name: str) -> str:
|
28
|
-
return """
|
29
|
-
openapi: 3.0.0
|
30
|
-
info:
|
31
|
-
version: 1.0.0
|
32
|
-
title: Mock API
|
33
|
-
description: Mock API Description
|
34
|
-
paths:
|
35
|
-
/test:
|
36
|
-
get:
|
37
|
-
summary: Test GET endpoint
|
38
|
-
operationId: testGet
|
39
|
-
responses:
|
40
|
-
'200':
|
41
|
-
description: Successful response
|
42
|
-
"""
|
43
|
-
|
44
|
-
|
45
|
-
# Fixture for a basic APIHubToolset
|
46
|
-
@pytest.fixture
|
47
|
-
def basic_apihub_toolset():
|
48
|
-
apihub_client = MockAPIHubClient()
|
49
|
-
tool = APIHubToolset(
|
50
|
-
apihub_resource_name='test_resource', apihub_client=apihub_client
|
51
|
-
)
|
52
|
-
return tool
|
53
|
-
|
54
|
-
|
55
|
-
# Fixture for an APIHubToolset with lazy loading
|
56
|
-
@pytest.fixture
|
57
|
-
def lazy_apihub_toolset():
|
58
|
-
apihub_client = MockAPIHubClient()
|
59
|
-
tool = APIHubToolset(
|
60
|
-
apihub_resource_name='test_resource',
|
61
|
-
apihub_client=apihub_client,
|
62
|
-
lazy_load_spec=True,
|
63
|
-
)
|
64
|
-
return tool
|
65
|
-
|
66
|
-
|
67
|
-
# Fixture for auth scheme
|
68
|
-
@pytest.fixture
|
69
|
-
def mock_auth_scheme():
|
70
|
-
return MagicMock(spec=AuthScheme)
|
71
|
-
|
72
|
-
|
73
|
-
# Fixture for auth credential
|
74
|
-
@pytest.fixture
|
75
|
-
def mock_auth_credential():
|
76
|
-
return MagicMock(spec=AuthCredential)
|
77
|
-
|
78
|
-
|
79
|
-
# Test cases
|
80
|
-
def test_apihub_toolset_initialization(basic_apihub_toolset):
|
81
|
-
assert basic_apihub_toolset.name == 'mock_api'
|
82
|
-
assert basic_apihub_toolset.description == 'Mock API Description'
|
83
|
-
assert basic_apihub_toolset.apihub_resource_name == 'test_resource'
|
84
|
-
assert not basic_apihub_toolset.lazy_load_spec
|
85
|
-
assert len(basic_apihub_toolset.generated_tools) == 1
|
86
|
-
assert 'test_get' in basic_apihub_toolset.generated_tools
|
87
|
-
|
88
|
-
|
89
|
-
def test_apihub_toolset_lazy_loading(lazy_apihub_toolset):
|
90
|
-
assert lazy_apihub_toolset.lazy_load_spec
|
91
|
-
assert not lazy_apihub_toolset.generated_tools
|
92
|
-
|
93
|
-
tools = lazy_apihub_toolset.get_tools()
|
94
|
-
assert len(tools) == 1
|
95
|
-
assert lazy_apihub_toolset.get_tool('test_get') == tools[0]
|
96
|
-
|
97
|
-
|
98
|
-
def test_apihub_toolset_no_title_in_spec(basic_apihub_toolset):
|
99
|
-
spec = """
|
100
|
-
openapi: 3.0.0
|
101
|
-
info:
|
102
|
-
version: 1.0.0
|
103
|
-
paths:
|
104
|
-
/empty_desc_test:
|
105
|
-
delete:
|
106
|
-
summary: Test DELETE endpoint
|
107
|
-
operationId: emptyDescTest
|
108
|
-
responses:
|
109
|
-
'200':
|
110
|
-
description: Successful response
|
111
|
-
"""
|
112
|
-
|
113
|
-
class MockAPIHubClientEmptySpec(BaseAPIHubClient):
|
114
|
-
|
115
|
-
def get_spec_content(self, apihub_resource_name: str) -> str:
|
116
|
-
return spec
|
117
|
-
|
118
|
-
apihub_client = MockAPIHubClientEmptySpec()
|
119
|
-
toolset = APIHubToolset(
|
120
|
-
apihub_resource_name='test_resource',
|
121
|
-
apihub_client=apihub_client,
|
122
|
-
)
|
123
|
-
|
124
|
-
assert toolset.name == 'unnamed'
|
125
|
-
|
126
|
-
|
127
|
-
def test_apihub_toolset_empty_description_in_spec():
|
128
|
-
spec = """
|
129
|
-
openapi: 3.0.0
|
130
|
-
info:
|
131
|
-
version: 1.0.0
|
132
|
-
title: Empty Description API
|
133
|
-
paths:
|
134
|
-
/empty_desc_test:
|
135
|
-
delete:
|
136
|
-
summary: Test DELETE endpoint
|
137
|
-
operationId: emptyDescTest
|
138
|
-
responses:
|
139
|
-
'200':
|
140
|
-
description: Successful response
|
141
|
-
"""
|
142
|
-
|
143
|
-
class MockAPIHubClientEmptySpec(BaseAPIHubClient):
|
144
|
-
|
145
|
-
def get_spec_content(self, apihub_resource_name: str) -> str:
|
146
|
-
return spec
|
147
|
-
|
148
|
-
apihub_client = MockAPIHubClientEmptySpec()
|
149
|
-
toolset = APIHubToolset(
|
150
|
-
apihub_resource_name='test_resource',
|
151
|
-
apihub_client=apihub_client,
|
152
|
-
)
|
153
|
-
|
154
|
-
assert toolset.name == 'empty_description_api'
|
155
|
-
assert toolset.description == ''
|
156
|
-
|
157
|
-
|
158
|
-
def test_get_tools_with_auth(mock_auth_scheme, mock_auth_credential):
|
159
|
-
apihub_client = MockAPIHubClient()
|
160
|
-
tool = APIHubToolset(
|
161
|
-
apihub_resource_name='test_resource',
|
162
|
-
apihub_client=apihub_client,
|
163
|
-
auth_scheme=mock_auth_scheme,
|
164
|
-
auth_credential=mock_auth_credential,
|
165
|
-
)
|
166
|
-
tools = tool.get_tools()
|
167
|
-
assert len(tools) == 1
|
168
|
-
|
169
|
-
|
170
|
-
def test_apihub_toolset_get_tools_lazy_load_empty_spec():
|
171
|
-
|
172
|
-
class MockAPIHubClientEmptySpec(BaseAPIHubClient):
|
173
|
-
|
174
|
-
def get_spec_content(self, apihub_resource_name: str) -> str:
|
175
|
-
return ''
|
176
|
-
|
177
|
-
apihub_client = MockAPIHubClientEmptySpec()
|
178
|
-
tool = APIHubToolset(
|
179
|
-
apihub_resource_name='test_resource',
|
180
|
-
apihub_client=apihub_client,
|
181
|
-
lazy_load_spec=True,
|
182
|
-
)
|
183
|
-
tools = tool.get_tools()
|
184
|
-
assert not tools
|
185
|
-
|
186
|
-
|
187
|
-
def test_apihub_toolset_get_tools_invalid_yaml():
|
188
|
-
|
189
|
-
class MockAPIHubClientInvalidYAML(BaseAPIHubClient):
|
190
|
-
|
191
|
-
def get_spec_content(self, apihub_resource_name: str) -> str:
|
192
|
-
return '{invalid yaml' # Return invalid YAML
|
193
|
-
|
194
|
-
with pytest.raises(yaml.YAMLError):
|
195
|
-
apihub_client = MockAPIHubClientInvalidYAML()
|
196
|
-
tool = APIHubToolset(
|
197
|
-
apihub_resource_name='test_resource',
|
198
|
-
apihub_client=apihub_client,
|
199
|
-
)
|
200
|
-
tool.get_tools()
|
201
|
-
|
202
|
-
|
203
|
-
if __name__ == '__main__':
|
204
|
-
pytest.main([__file__])
|