google-adk 0.0.1__py3-none-any.whl → 0.0.2__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/__init__.py +20 -0
- google/adk/agents/__init__.py +32 -0
- google/adk/agents/active_streaming_tool.py +38 -0
- google/adk/agents/base_agent.py +345 -0
- google/adk/agents/callback_context.py +112 -0
- google/adk/agents/invocation_context.py +181 -0
- google/adk/agents/langgraph_agent.py +140 -0
- google/adk/agents/live_request_queue.py +64 -0
- google/adk/agents/llm_agent.py +376 -0
- google/adk/agents/loop_agent.py +62 -0
- google/adk/agents/parallel_agent.py +96 -0
- google/adk/agents/readonly_context.py +46 -0
- google/adk/agents/remote_agent.py +50 -0
- google/adk/agents/run_config.py +87 -0
- google/adk/agents/sequential_agent.py +45 -0
- google/adk/agents/transcription_entry.py +34 -0
- google/adk/artifacts/__init__.py +23 -0
- google/adk/artifacts/base_artifact_service.py +128 -0
- google/adk/artifacts/gcs_artifact_service.py +195 -0
- google/adk/artifacts/in_memory_artifact_service.py +133 -0
- google/adk/auth/__init__.py +22 -0
- google/adk/auth/auth_credential.py +220 -0
- google/adk/auth/auth_handler.py +268 -0
- google/adk/auth/auth_preprocessor.py +116 -0
- google/adk/auth/auth_schemes.py +67 -0
- google/adk/auth/auth_tool.py +55 -0
- google/adk/cli/__init__.py +15 -0
- google/adk/cli/__main__.py +18 -0
- google/adk/cli/agent_graph.py +122 -0
- google/adk/cli/browser/adk_favicon.svg +17 -0
- google/adk/cli/browser/assets/audio-processor.js +51 -0
- google/adk/cli/browser/assets/config/runtime-config.json +3 -0
- google/adk/cli/browser/index.html +33 -0
- google/adk/cli/browser/main-XUU6OGCC.js +75 -0
- google/adk/cli/browser/polyfills-FFHMD2TL.js +18 -0
- google/adk/cli/browser/styles-4VDSPQ37.css +17 -0
- google/adk/cli/cli.py +181 -0
- google/adk/cli/cli_deploy.py +181 -0
- google/adk/cli/cli_eval.py +282 -0
- google/adk/cli/cli_tools_click.py +479 -0
- google/adk/cli/fast_api.py +774 -0
- google/adk/cli/media_streamer/__init__.py +19 -0
- google/adk/cli/media_streamer/index.html +228 -0
- google/adk/cli/utils/__init__.py +49 -0
- google/adk/cli/utils/envs.py +57 -0
- google/adk/cli/utils/evals.py +93 -0
- google/adk/cli/utils/logs.py +72 -0
- google/adk/code_executors/__init__.py +49 -0
- google/adk/code_executors/base_code_executor.py +97 -0
- google/adk/code_executors/code_execution_utils.py +256 -0
- google/adk/code_executors/code_executor_context.py +202 -0
- google/adk/code_executors/container_code_executor.py +196 -0
- google/adk/code_executors/unsafe_local_code_executor.py +71 -0
- google/adk/code_executors/vertex_ai_code_executor.py +234 -0
- google/adk/evaluation/__init__.py +31 -0
- google/adk/evaluation/agent_evaluator.py +329 -0
- google/adk/evaluation/evaluation_constants.py +24 -0
- google/adk/evaluation/evaluation_generator.py +270 -0
- google/adk/evaluation/response_evaluator.py +135 -0
- google/adk/evaluation/trajectory_evaluator.py +184 -0
- google/adk/events/__init__.py +21 -0
- google/adk/events/event.py +130 -0
- google/adk/events/event_actions.py +55 -0
- google/adk/examples/__init__.py +28 -0
- google/adk/examples/base_example_provider.py +35 -0
- google/adk/examples/example.py +27 -0
- google/adk/examples/example_util.py +123 -0
- google/adk/examples/vertex_ai_example_store.py +104 -0
- google/adk/flows/__init__.py +14 -0
- google/adk/flows/llm_flows/__init__.py +20 -0
- google/adk/flows/llm_flows/_base_llm_processor.py +52 -0
- google/adk/flows/llm_flows/_code_execution.py +458 -0
- google/adk/flows/llm_flows/_nl_planning.py +129 -0
- google/adk/flows/llm_flows/agent_transfer.py +132 -0
- google/adk/flows/llm_flows/audio_transcriber.py +109 -0
- google/adk/flows/llm_flows/auto_flow.py +49 -0
- google/adk/flows/llm_flows/base_llm_flow.py +559 -0
- google/adk/flows/llm_flows/basic.py +72 -0
- google/adk/flows/llm_flows/contents.py +370 -0
- google/adk/flows/llm_flows/functions.py +486 -0
- google/adk/flows/llm_flows/identity.py +47 -0
- google/adk/flows/llm_flows/instructions.py +137 -0
- google/adk/flows/llm_flows/single_flow.py +57 -0
- google/adk/memory/__init__.py +35 -0
- google/adk/memory/base_memory_service.py +74 -0
- google/adk/memory/in_memory_memory_service.py +62 -0
- google/adk/memory/vertex_ai_rag_memory_service.py +177 -0
- google/adk/models/__init__.py +31 -0
- google/adk/models/anthropic_llm.py +243 -0
- google/adk/models/base_llm.py +87 -0
- google/adk/models/base_llm_connection.py +76 -0
- google/adk/models/gemini_llm_connection.py +200 -0
- google/adk/models/google_llm.py +331 -0
- google/adk/models/lite_llm.py +673 -0
- google/adk/models/llm_request.py +98 -0
- google/adk/models/llm_response.py +111 -0
- google/adk/models/registry.py +102 -0
- google/adk/planners/__init__.py +23 -0
- google/adk/planners/base_planner.py +66 -0
- google/adk/planners/built_in_planner.py +75 -0
- google/adk/planners/plan_re_act_planner.py +208 -0
- google/adk/runners.py +456 -0
- google/adk/sessions/__init__.py +41 -0
- google/adk/sessions/base_session_service.py +133 -0
- google/adk/sessions/database_session_service.py +522 -0
- google/adk/sessions/in_memory_session_service.py +206 -0
- google/adk/sessions/session.py +54 -0
- google/adk/sessions/state.py +71 -0
- google/adk/sessions/vertex_ai_session_service.py +356 -0
- google/adk/telemetry.py +189 -0
- google/adk/tests/__init__.py +14 -0
- google/adk/tests/integration/.env.example +10 -0
- google/adk/tests/integration/__init__.py +18 -0
- google/adk/tests/integration/conftest.py +119 -0
- google/adk/tests/integration/fixture/__init__.py +14 -0
- google/adk/tests/integration/fixture/agent_with_config/__init__.py +15 -0
- google/adk/tests/integration/fixture/agent_with_config/agent.py +88 -0
- google/adk/tests/integration/fixture/callback_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/callback_agent/agent.py +105 -0
- google/adk/tests/integration/fixture/context_update_test/OWNERS +1 -0
- google/adk/tests/integration/fixture/context_update_test/__init__.py +15 -0
- google/adk/tests/integration/fixture/context_update_test/agent.py +43 -0
- google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +582 -0
- google/adk/tests/integration/fixture/context_variable_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/context_variable_agent/agent.py +115 -0
- google/adk/tests/integration/fixture/customer_support_ma/__init__.py +15 -0
- google/adk/tests/integration/fixture/customer_support_ma/agent.py +172 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +338 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +69 -0
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +6 -0
- google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +15 -0
- google/adk/tests/integration/fixture/flow_complex_spark/agent.py +182 -0
- google/adk/tests/integration/fixture/flow_complex_spark/sample.debug.log +243 -0
- google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +190 -0
- google/adk/tests/integration/fixture/hello_world_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/hello_world_agent/agent.py +95 -0
- google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +24 -0
- google/adk/tests/integration/fixture/hello_world_agent/test_config.json +6 -0
- google/adk/tests/integration/fixture/home_automation_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/home_automation_agent/agent.py +304 -0
- google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_config.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +18 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +17 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +6 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +18 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +17 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +5 -0
- google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +5 -0
- google/adk/tests/integration/fixture/tool_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/tool_agent/agent.py +218 -0
- google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
- google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +15 -0
- google/adk/tests/integration/fixture/trip_planner_agent/agent.py +110 -0
- google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +13 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +5 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +13 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +5 -0
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +7 -0
- google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +19 -0
- google/adk/tests/integration/models/__init__.py +14 -0
- google/adk/tests/integration/models/test_google_llm.py +65 -0
- google/adk/tests/integration/test_callback.py +70 -0
- google/adk/tests/integration/test_context_variable.py +67 -0
- google/adk/tests/integration/test_evalute_agent_in_fixture.py +76 -0
- google/adk/tests/integration/test_multi_agent.py +28 -0
- google/adk/tests/integration/test_multi_turn.py +42 -0
- google/adk/tests/integration/test_single_agent.py +23 -0
- google/adk/tests/integration/test_sub_agent.py +26 -0
- google/adk/tests/integration/test_system_instruction.py +177 -0
- google/adk/tests/integration/test_tools.py +287 -0
- google/adk/tests/integration/test_with_test_file.py +34 -0
- google/adk/tests/integration/tools/__init__.py +14 -0
- google/adk/tests/integration/utils/__init__.py +16 -0
- google/adk/tests/integration/utils/asserts.py +75 -0
- google/adk/tests/integration/utils/test_runner.py +97 -0
- google/adk/tests/unittests/__init__.py +14 -0
- google/adk/tests/unittests/agents/__init__.py +14 -0
- google/adk/tests/unittests/agents/test_base_agent.py +407 -0
- google/adk/tests/unittests/agents/test_langgraph_agent.py +191 -0
- google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +138 -0
- google/adk/tests/unittests/agents/test_llm_agent_fields.py +231 -0
- google/adk/tests/unittests/agents/test_loop_agent.py +136 -0
- google/adk/tests/unittests/agents/test_parallel_agent.py +92 -0
- google/adk/tests/unittests/agents/test_sequential_agent.py +114 -0
- google/adk/tests/unittests/artifacts/__init__.py +14 -0
- google/adk/tests/unittests/artifacts/test_artifact_service.py +276 -0
- google/adk/tests/unittests/auth/test_auth_handler.py +575 -0
- google/adk/tests/unittests/conftest.py +73 -0
- google/adk/tests/unittests/fast_api/__init__.py +14 -0
- google/adk/tests/unittests/fast_api/test_fast_api.py +269 -0
- google/adk/tests/unittests/flows/__init__.py +14 -0
- google/adk/tests/unittests/flows/llm_flows/__init__.py +14 -0
- google/adk/tests/unittests/flows/llm_flows/_test_examples.py +142 -0
- google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +311 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +244 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +346 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +93 -0
- google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +258 -0
- google/adk/tests/unittests/flows/llm_flows/test_identity.py +66 -0
- google/adk/tests/unittests/flows/llm_flows/test_instructions.py +164 -0
- google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +142 -0
- google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +46 -0
- google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +269 -0
- google/adk/tests/unittests/models/__init__.py +14 -0
- google/adk/tests/unittests/models/test_google_llm.py +224 -0
- google/adk/tests/unittests/models/test_litellm.py +804 -0
- google/adk/tests/unittests/models/test_models.py +60 -0
- google/adk/tests/unittests/sessions/__init__.py +14 -0
- google/adk/tests/unittests/sessions/test_session_service.py +227 -0
- google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +246 -0
- google/adk/tests/unittests/streaming/__init__.py +14 -0
- google/adk/tests/unittests/streaming/test_streaming.py +50 -0
- google/adk/tests/unittests/tools/__init__.py +14 -0
- google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +499 -0
- google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +204 -0
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +600 -0
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +630 -0
- google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +345 -0
- google/adk/tests/unittests/tools/google_api_tool/__init__.py +13 -0
- google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +657 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +145 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +68 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +153 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +196 -0
- google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +573 -0
- google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +436 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +1367 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +628 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +139 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +406 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +966 -0
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +201 -0
- google/adk/tests/unittests/tools/retrieval/__init__.py +14 -0
- google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +147 -0
- google/adk/tests/unittests/tools/test_agent_tool.py +167 -0
- google/adk/tests/unittests/tools/test_base_tool.py +141 -0
- google/adk/tests/unittests/tools/test_build_function_declaration.py +277 -0
- google/adk/tests/unittests/utils.py +304 -0
- google/adk/tools/__init__.py +51 -0
- google/adk/tools/_automatic_function_calling_util.py +346 -0
- google/adk/tools/agent_tool.py +176 -0
- google/adk/tools/apihub_tool/__init__.py +19 -0
- google/adk/tools/apihub_tool/apihub_toolset.py +209 -0
- google/adk/tools/apihub_tool/clients/__init__.py +13 -0
- google/adk/tools/apihub_tool/clients/apihub_client.py +332 -0
- google/adk/tools/apihub_tool/clients/secret_client.py +115 -0
- google/adk/tools/application_integration_tool/__init__.py +19 -0
- google/adk/tools/application_integration_tool/application_integration_toolset.py +230 -0
- google/adk/tools/application_integration_tool/clients/connections_client.py +903 -0
- google/adk/tools/application_integration_tool/clients/integration_client.py +253 -0
- google/adk/tools/base_tool.py +144 -0
- google/adk/tools/built_in_code_execution_tool.py +59 -0
- google/adk/tools/crewai_tool.py +72 -0
- google/adk/tools/example_tool.py +62 -0
- google/adk/tools/exit_loop_tool.py +23 -0
- google/adk/tools/function_parameter_parse_util.py +307 -0
- google/adk/tools/function_tool.py +87 -0
- google/adk/tools/get_user_choice_tool.py +28 -0
- google/adk/tools/google_api_tool/__init__.py +14 -0
- google/adk/tools/google_api_tool/google_api_tool.py +59 -0
- google/adk/tools/google_api_tool/google_api_tool_set.py +107 -0
- google/adk/tools/google_api_tool/google_api_tool_sets.py +55 -0
- google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +521 -0
- google/adk/tools/google_search_tool.py +68 -0
- google/adk/tools/langchain_tool.py +86 -0
- google/adk/tools/load_artifacts_tool.py +113 -0
- google/adk/tools/load_memory_tool.py +58 -0
- google/adk/tools/load_web_page.py +41 -0
- google/adk/tools/long_running_tool.py +39 -0
- google/adk/tools/mcp_tool/__init__.py +42 -0
- google/adk/tools/mcp_tool/conversion_utils.py +161 -0
- google/adk/tools/mcp_tool/mcp_tool.py +113 -0
- google/adk/tools/mcp_tool/mcp_toolset.py +272 -0
- google/adk/tools/openapi_tool/__init__.py +21 -0
- google/adk/tools/openapi_tool/auth/__init__.py +19 -0
- google/adk/tools/openapi_tool/auth/auth_helpers.py +498 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/__init__.py +25 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/auto_auth_credential_exchanger.py +105 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +55 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/oauth2_exchanger.py +117 -0
- google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +97 -0
- google/adk/tools/openapi_tool/common/__init__.py +19 -0
- google/adk/tools/openapi_tool/common/common.py +300 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +32 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py +231 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +144 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +260 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +496 -0
- google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +268 -0
- google/adk/tools/preload_memory_tool.py +72 -0
- google/adk/tools/retrieval/__init__.py +36 -0
- google/adk/tools/retrieval/base_retrieval_tool.py +37 -0
- google/adk/tools/retrieval/files_retrieval.py +33 -0
- google/adk/tools/retrieval/llama_index_retrieval.py +41 -0
- google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +107 -0
- google/adk/tools/tool_context.py +90 -0
- google/adk/tools/toolbox_tool.py +46 -0
- google/adk/tools/transfer_to_agent_tool.py +21 -0
- google/adk/tools/vertex_ai_search_tool.py +96 -0
- google/adk/version.py +16 -0
- google_adk-0.0.1.dist-info/LICENSE.txt → google_adk-0.0.2.dist-info/LICENSE +32 -0
- google_adk-0.0.2.dist-info/METADATA +73 -0
- google_adk-0.0.2.dist-info/RECORD +308 -0
- {google_adk-0.0.1.dist-info → google_adk-0.0.2.dist-info}/WHEEL +1 -2
- google_adk-0.0.2.dist-info/entry_points.txt +3 -0
- agent_kit/__init__.py +0 -0
- google_adk-0.0.1.dist-info/METADATA +0 -15
- google_adk-0.0.1.dist-info/RECORD +0 -6
- google_adk-0.0.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,657 @@
|
|
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.tools.google_api_tool.googleapi_to_openapi_converter import GoogleApiToOpenApiConverter
|
18
|
+
# Import the converter class
|
19
|
+
from googleapiclient.errors import HttpError
|
20
|
+
import pytest
|
21
|
+
|
22
|
+
|
23
|
+
@pytest.fixture
|
24
|
+
def calendar_api_spec():
|
25
|
+
"""Fixture that provides a mock Google Calendar API spec for testing."""
|
26
|
+
return {
|
27
|
+
"kind": "discovery#restDescription",
|
28
|
+
"id": "calendar:v3",
|
29
|
+
"name": "calendar",
|
30
|
+
"version": "v3",
|
31
|
+
"title": "Google Calendar API",
|
32
|
+
"description": "Accesses the Google Calendar API",
|
33
|
+
"documentationLink": "https://developers.google.com/calendar/",
|
34
|
+
"protocol": "rest",
|
35
|
+
"rootUrl": "https://www.googleapis.com/",
|
36
|
+
"servicePath": "calendar/v3/",
|
37
|
+
"auth": {
|
38
|
+
"oauth2": {
|
39
|
+
"scopes": {
|
40
|
+
"https://www.googleapis.com/auth/calendar": {
|
41
|
+
"description": "Full access to Google Calendar"
|
42
|
+
},
|
43
|
+
"https://www.googleapis.com/auth/calendar.readonly": {
|
44
|
+
"description": "Read-only access to Google Calendar"
|
45
|
+
},
|
46
|
+
}
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"schemas": {
|
50
|
+
"Calendar": {
|
51
|
+
"type": "object",
|
52
|
+
"description": "A calendar resource",
|
53
|
+
"properties": {
|
54
|
+
"id": {
|
55
|
+
"type": "string",
|
56
|
+
"description": "Calendar identifier",
|
57
|
+
},
|
58
|
+
"summary": {
|
59
|
+
"type": "string",
|
60
|
+
"description": "Calendar summary",
|
61
|
+
"required": True,
|
62
|
+
},
|
63
|
+
"timeZone": {
|
64
|
+
"type": "string",
|
65
|
+
"description": "Calendar timezone",
|
66
|
+
},
|
67
|
+
},
|
68
|
+
},
|
69
|
+
"Event": {
|
70
|
+
"type": "object",
|
71
|
+
"description": "An event resource",
|
72
|
+
"properties": {
|
73
|
+
"id": {"type": "string", "description": "Event identifier"},
|
74
|
+
"summary": {"type": "string", "description": "Event summary"},
|
75
|
+
"start": {"$ref": "EventDateTime"},
|
76
|
+
"end": {"$ref": "EventDateTime"},
|
77
|
+
"attendees": {
|
78
|
+
"type": "array",
|
79
|
+
"description": "Event attendees",
|
80
|
+
"items": {"$ref": "EventAttendee"},
|
81
|
+
},
|
82
|
+
},
|
83
|
+
},
|
84
|
+
"EventDateTime": {
|
85
|
+
"type": "object",
|
86
|
+
"description": "Date/time for an event",
|
87
|
+
"properties": {
|
88
|
+
"dateTime": {
|
89
|
+
"type": "string",
|
90
|
+
"format": "date-time",
|
91
|
+
"description": "Date/time in RFC3339 format",
|
92
|
+
},
|
93
|
+
"timeZone": {
|
94
|
+
"type": "string",
|
95
|
+
"description": "Timezone for the date/time",
|
96
|
+
},
|
97
|
+
},
|
98
|
+
},
|
99
|
+
"EventAttendee": {
|
100
|
+
"type": "object",
|
101
|
+
"description": "An attendee of an event",
|
102
|
+
"properties": {
|
103
|
+
"email": {"type": "string", "description": "Attendee email"},
|
104
|
+
"responseStatus": {
|
105
|
+
"type": "string",
|
106
|
+
"description": "Response status",
|
107
|
+
"enum": [
|
108
|
+
"needsAction",
|
109
|
+
"declined",
|
110
|
+
"tentative",
|
111
|
+
"accepted",
|
112
|
+
],
|
113
|
+
},
|
114
|
+
},
|
115
|
+
},
|
116
|
+
},
|
117
|
+
"resources": {
|
118
|
+
"calendars": {
|
119
|
+
"methods": {
|
120
|
+
"get": {
|
121
|
+
"id": "calendar.calendars.get",
|
122
|
+
"path": "calendars/{calendarId}",
|
123
|
+
"httpMethod": "GET",
|
124
|
+
"description": "Returns metadata for a calendar.",
|
125
|
+
"parameters": {
|
126
|
+
"calendarId": {
|
127
|
+
"type": "string",
|
128
|
+
"description": "Calendar identifier",
|
129
|
+
"required": True,
|
130
|
+
"location": "path",
|
131
|
+
}
|
132
|
+
},
|
133
|
+
"response": {"$ref": "Calendar"},
|
134
|
+
"scopes": [
|
135
|
+
"https://www.googleapis.com/auth/calendar",
|
136
|
+
"https://www.googleapis.com/auth/calendar.readonly",
|
137
|
+
],
|
138
|
+
},
|
139
|
+
"insert": {
|
140
|
+
"id": "calendar.calendars.insert",
|
141
|
+
"path": "calendars",
|
142
|
+
"httpMethod": "POST",
|
143
|
+
"description": "Creates a secondary calendar.",
|
144
|
+
"request": {"$ref": "Calendar"},
|
145
|
+
"response": {"$ref": "Calendar"},
|
146
|
+
"scopes": ["https://www.googleapis.com/auth/calendar"],
|
147
|
+
},
|
148
|
+
},
|
149
|
+
"resources": {
|
150
|
+
"events": {
|
151
|
+
"methods": {
|
152
|
+
"list": {
|
153
|
+
"id": "calendar.events.list",
|
154
|
+
"path": "calendars/{calendarId}/events",
|
155
|
+
"httpMethod": "GET",
|
156
|
+
"description": (
|
157
|
+
"Returns events on the specified calendar."
|
158
|
+
),
|
159
|
+
"parameters": {
|
160
|
+
"calendarId": {
|
161
|
+
"type": "string",
|
162
|
+
"description": "Calendar identifier",
|
163
|
+
"required": True,
|
164
|
+
"location": "path",
|
165
|
+
},
|
166
|
+
"maxResults": {
|
167
|
+
"type": "integer",
|
168
|
+
"description": (
|
169
|
+
"Maximum number of events returned"
|
170
|
+
),
|
171
|
+
"format": "int32",
|
172
|
+
"minimum": "1",
|
173
|
+
"maximum": "2500",
|
174
|
+
"default": "250",
|
175
|
+
"location": "query",
|
176
|
+
},
|
177
|
+
"orderBy": {
|
178
|
+
"type": "string",
|
179
|
+
"description": (
|
180
|
+
"Order of the events returned"
|
181
|
+
),
|
182
|
+
"enum": ["startTime", "updated"],
|
183
|
+
"location": "query",
|
184
|
+
},
|
185
|
+
},
|
186
|
+
"response": {"$ref": "Events"},
|
187
|
+
"scopes": [
|
188
|
+
"https://www.googleapis.com/auth/calendar",
|
189
|
+
"https://www.googleapis.com/auth/calendar.readonly",
|
190
|
+
],
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
},
|
195
|
+
}
|
196
|
+
},
|
197
|
+
}
|
198
|
+
|
199
|
+
|
200
|
+
@pytest.fixture
|
201
|
+
def converter():
|
202
|
+
"""Fixture that provides a basic converter instance."""
|
203
|
+
return GoogleApiToOpenApiConverter("calendar", "v3")
|
204
|
+
|
205
|
+
|
206
|
+
@pytest.fixture
|
207
|
+
def mock_api_resource(calendar_api_spec):
|
208
|
+
"""Fixture that provides a mock API resource with the test spec."""
|
209
|
+
mock_resource = MagicMock()
|
210
|
+
mock_resource._rootDesc = calendar_api_spec
|
211
|
+
return mock_resource
|
212
|
+
|
213
|
+
|
214
|
+
@pytest.fixture
|
215
|
+
def prepared_converter(converter, calendar_api_spec):
|
216
|
+
"""Fixture that provides a converter with the API spec already set."""
|
217
|
+
converter.google_api_spec = calendar_api_spec
|
218
|
+
return converter
|
219
|
+
|
220
|
+
|
221
|
+
@pytest.fixture
|
222
|
+
def converter_with_patched_build(monkeypatch, mock_api_resource):
|
223
|
+
"""Fixture that provides a converter with the build function patched.
|
224
|
+
|
225
|
+
This simulates a successful API spec fetch.
|
226
|
+
"""
|
227
|
+
# Create a mock for the build function
|
228
|
+
mock_build = MagicMock(return_value=mock_api_resource)
|
229
|
+
|
230
|
+
# Patch the build function in the target module
|
231
|
+
monkeypatch.setattr(
|
232
|
+
"google.adk.tools.google_api_tool.googleapi_to_openapi_converter.build",
|
233
|
+
mock_build,
|
234
|
+
)
|
235
|
+
|
236
|
+
# Create and return a converter instance
|
237
|
+
return GoogleApiToOpenApiConverter("calendar", "v3")
|
238
|
+
|
239
|
+
|
240
|
+
class TestGoogleApiToOpenApiConverter:
|
241
|
+
"""Test suite for the GoogleApiToOpenApiConverter class."""
|
242
|
+
|
243
|
+
def test_init(self, converter):
|
244
|
+
"""Test converter initialization."""
|
245
|
+
assert converter.api_name == "calendar"
|
246
|
+
assert converter.api_version == "v3"
|
247
|
+
assert converter.google_api_resource is None
|
248
|
+
assert converter.google_api_spec is None
|
249
|
+
assert converter.openapi_spec["openapi"] == "3.0.0"
|
250
|
+
assert "info" in converter.openapi_spec
|
251
|
+
assert "paths" in converter.openapi_spec
|
252
|
+
assert "components" in converter.openapi_spec
|
253
|
+
|
254
|
+
def test_fetch_google_api_spec(
|
255
|
+
self, converter_with_patched_build, calendar_api_spec
|
256
|
+
):
|
257
|
+
"""Test fetching Google API specification."""
|
258
|
+
# Call the method
|
259
|
+
converter_with_patched_build.fetch_google_api_spec()
|
260
|
+
|
261
|
+
# Verify the results
|
262
|
+
assert converter_with_patched_build.google_api_spec == calendar_api_spec
|
263
|
+
|
264
|
+
def test_fetch_google_api_spec_error(self, monkeypatch, converter):
|
265
|
+
"""Test error handling when fetching Google API specification."""
|
266
|
+
# Create a mock that raises an error
|
267
|
+
mock_build = MagicMock(
|
268
|
+
side_effect=HttpError(resp=MagicMock(status=404), content=b"Not Found")
|
269
|
+
)
|
270
|
+
monkeypatch.setattr(
|
271
|
+
"google.adk.tools.google_api_tool.googleapi_to_openapi_converter.build",
|
272
|
+
mock_build,
|
273
|
+
)
|
274
|
+
|
275
|
+
# Verify exception is raised
|
276
|
+
with pytest.raises(HttpError):
|
277
|
+
converter.fetch_google_api_spec()
|
278
|
+
|
279
|
+
def test_convert_info(self, prepared_converter):
|
280
|
+
"""Test conversion of basic API information."""
|
281
|
+
# Call the method
|
282
|
+
prepared_converter._convert_info()
|
283
|
+
|
284
|
+
# Verify the results
|
285
|
+
info = prepared_converter.openapi_spec["info"]
|
286
|
+
assert info["title"] == "Google Calendar API"
|
287
|
+
assert info["description"] == "Accesses the Google Calendar API"
|
288
|
+
assert info["version"] == "v3"
|
289
|
+
assert info["termsOfService"] == "https://developers.google.com/calendar/"
|
290
|
+
|
291
|
+
# Check external docs
|
292
|
+
external_docs = prepared_converter.openapi_spec["externalDocs"]
|
293
|
+
assert external_docs["url"] == "https://developers.google.com/calendar/"
|
294
|
+
|
295
|
+
def test_convert_servers(self, prepared_converter):
|
296
|
+
"""Test conversion of server information."""
|
297
|
+
# Call the method
|
298
|
+
prepared_converter._convert_servers()
|
299
|
+
|
300
|
+
# Verify the results
|
301
|
+
servers = prepared_converter.openapi_spec["servers"]
|
302
|
+
assert len(servers) == 1
|
303
|
+
assert servers[0]["url"] == "https://www.googleapis.com/calendar/v3"
|
304
|
+
assert servers[0]["description"] == "calendar v3 API"
|
305
|
+
|
306
|
+
def test_convert_security_schemes(self, prepared_converter):
|
307
|
+
"""Test conversion of security schemes."""
|
308
|
+
# Call the method
|
309
|
+
prepared_converter._convert_security_schemes()
|
310
|
+
|
311
|
+
# Verify the results
|
312
|
+
security_schemes = prepared_converter.openapi_spec["components"][
|
313
|
+
"securitySchemes"
|
314
|
+
]
|
315
|
+
|
316
|
+
# Check OAuth2 configuration
|
317
|
+
assert "oauth2" in security_schemes
|
318
|
+
oauth2 = security_schemes["oauth2"]
|
319
|
+
assert oauth2["type"] == "oauth2"
|
320
|
+
|
321
|
+
# Check OAuth2 scopes
|
322
|
+
scopes = oauth2["flows"]["authorizationCode"]["scopes"]
|
323
|
+
assert "https://www.googleapis.com/auth/calendar" in scopes
|
324
|
+
assert "https://www.googleapis.com/auth/calendar.readonly" in scopes
|
325
|
+
|
326
|
+
# Check API key configuration
|
327
|
+
assert "apiKey" in security_schemes
|
328
|
+
assert security_schemes["apiKey"]["type"] == "apiKey"
|
329
|
+
assert security_schemes["apiKey"]["in"] == "query"
|
330
|
+
assert security_schemes["apiKey"]["name"] == "key"
|
331
|
+
|
332
|
+
def test_convert_schemas(self, prepared_converter):
|
333
|
+
"""Test conversion of schema definitions."""
|
334
|
+
# Call the method
|
335
|
+
prepared_converter._convert_schemas()
|
336
|
+
|
337
|
+
# Verify the results
|
338
|
+
schemas = prepared_converter.openapi_spec["components"]["schemas"]
|
339
|
+
|
340
|
+
# Check Calendar schema
|
341
|
+
assert "Calendar" in schemas
|
342
|
+
calendar_schema = schemas["Calendar"]
|
343
|
+
assert calendar_schema["type"] == "object"
|
344
|
+
assert calendar_schema["description"] == "A calendar resource"
|
345
|
+
|
346
|
+
# Check required properties
|
347
|
+
assert "required" in calendar_schema
|
348
|
+
assert "summary" in calendar_schema["required"]
|
349
|
+
|
350
|
+
# Check Event schema references
|
351
|
+
assert "Event" in schemas
|
352
|
+
event_schema = schemas["Event"]
|
353
|
+
assert (
|
354
|
+
event_schema["properties"]["start"]["$ref"]
|
355
|
+
== "#/components/schemas/EventDateTime"
|
356
|
+
)
|
357
|
+
|
358
|
+
# Check array type with references
|
359
|
+
attendees_schema = event_schema["properties"]["attendees"]
|
360
|
+
assert attendees_schema["type"] == "array"
|
361
|
+
assert (
|
362
|
+
attendees_schema["items"]["$ref"]
|
363
|
+
== "#/components/schemas/EventAttendee"
|
364
|
+
)
|
365
|
+
|
366
|
+
# Check enum values
|
367
|
+
attendee_schema = schemas["EventAttendee"]
|
368
|
+
response_status = attendee_schema["properties"]["responseStatus"]
|
369
|
+
assert "enum" in response_status
|
370
|
+
assert "accepted" in response_status["enum"]
|
371
|
+
|
372
|
+
@pytest.mark.parametrize(
|
373
|
+
"schema_def, expected_type, expected_attrs",
|
374
|
+
[
|
375
|
+
# Test object type
|
376
|
+
(
|
377
|
+
{
|
378
|
+
"type": "object",
|
379
|
+
"description": "Test object",
|
380
|
+
"properties": {
|
381
|
+
"id": {"type": "string", "required": True},
|
382
|
+
"name": {"type": "string"},
|
383
|
+
},
|
384
|
+
},
|
385
|
+
"object",
|
386
|
+
{"description": "Test object", "required": ["id"]},
|
387
|
+
),
|
388
|
+
# Test array type
|
389
|
+
(
|
390
|
+
{
|
391
|
+
"type": "array",
|
392
|
+
"description": "Test array",
|
393
|
+
"items": {"type": "string"},
|
394
|
+
},
|
395
|
+
"array",
|
396
|
+
{"description": "Test array", "items": {"type": "string"}},
|
397
|
+
),
|
398
|
+
# Test reference conversion
|
399
|
+
(
|
400
|
+
{"$ref": "Calendar"},
|
401
|
+
None, # No type for references
|
402
|
+
{"$ref": "#/components/schemas/Calendar"},
|
403
|
+
),
|
404
|
+
# Test enum conversion
|
405
|
+
(
|
406
|
+
{"type": "string", "enum": ["value1", "value2"]},
|
407
|
+
"string",
|
408
|
+
{"enum": ["value1", "value2"]},
|
409
|
+
),
|
410
|
+
],
|
411
|
+
)
|
412
|
+
def test_convert_schema_object(
|
413
|
+
self, converter, schema_def, expected_type, expected_attrs
|
414
|
+
):
|
415
|
+
"""Test conversion of individual schema objects with different input variations."""
|
416
|
+
converted = converter._convert_schema_object(schema_def)
|
417
|
+
|
418
|
+
# Check type if expected
|
419
|
+
if expected_type:
|
420
|
+
assert converted["type"] == expected_type
|
421
|
+
|
422
|
+
# Check other expected attributes
|
423
|
+
for key, value in expected_attrs.items():
|
424
|
+
assert converted[key] == value
|
425
|
+
|
426
|
+
@pytest.mark.parametrize(
|
427
|
+
"path, expected_params",
|
428
|
+
[
|
429
|
+
# Path with parameters
|
430
|
+
(
|
431
|
+
"/calendars/{calendarId}/events/{eventId}",
|
432
|
+
["calendarId", "eventId"],
|
433
|
+
),
|
434
|
+
# Path without parameters
|
435
|
+
("/calendars/events", []),
|
436
|
+
# Mixed path
|
437
|
+
("/users/{userId}/calendars/default", ["userId"]),
|
438
|
+
],
|
439
|
+
)
|
440
|
+
def test_extract_path_parameters(self, converter, path, expected_params):
|
441
|
+
"""Test extraction of path parameters from URL path with various inputs."""
|
442
|
+
params = converter._extract_path_parameters(path)
|
443
|
+
assert set(params) == set(expected_params)
|
444
|
+
assert len(params) == len(expected_params)
|
445
|
+
|
446
|
+
@pytest.mark.parametrize(
|
447
|
+
"param_data, expected_result",
|
448
|
+
[
|
449
|
+
# String parameter
|
450
|
+
(
|
451
|
+
{
|
452
|
+
"type": "string",
|
453
|
+
"description": "String parameter",
|
454
|
+
"pattern": "^[a-z]+$",
|
455
|
+
},
|
456
|
+
{"type": "string", "pattern": "^[a-z]+$"},
|
457
|
+
),
|
458
|
+
# Integer parameter with format
|
459
|
+
(
|
460
|
+
{"type": "integer", "format": "int32", "default": "10"},
|
461
|
+
{"type": "integer", "format": "int32", "default": "10"},
|
462
|
+
),
|
463
|
+
# Enum parameter
|
464
|
+
(
|
465
|
+
{"type": "string", "enum": ["option1", "option2"]},
|
466
|
+
{"type": "string", "enum": ["option1", "option2"]},
|
467
|
+
),
|
468
|
+
],
|
469
|
+
)
|
470
|
+
def test_convert_parameter_schema(
|
471
|
+
self, converter, param_data, expected_result
|
472
|
+
):
|
473
|
+
"""Test conversion of parameter definitions to OpenAPI schemas."""
|
474
|
+
converted = converter._convert_parameter_schema(param_data)
|
475
|
+
|
476
|
+
# Check all expected attributes
|
477
|
+
for key, value in expected_result.items():
|
478
|
+
assert converted[key] == value
|
479
|
+
|
480
|
+
def test_convert(self, converter_with_patched_build):
|
481
|
+
"""Test the complete conversion process."""
|
482
|
+
# Call the method
|
483
|
+
result = converter_with_patched_build.convert()
|
484
|
+
|
485
|
+
# Verify basic structure
|
486
|
+
assert result["openapi"] == "3.0.0"
|
487
|
+
assert "info" in result
|
488
|
+
assert "servers" in result
|
489
|
+
assert "paths" in result
|
490
|
+
assert "components" in result
|
491
|
+
|
492
|
+
# Verify paths
|
493
|
+
paths = result["paths"]
|
494
|
+
assert "/calendars/{calendarId}" in paths
|
495
|
+
assert "get" in paths["/calendars/{calendarId}"]
|
496
|
+
|
497
|
+
# Verify nested resources
|
498
|
+
assert "/calendars/{calendarId}/events" in paths
|
499
|
+
|
500
|
+
# Verify method details
|
501
|
+
get_calendar = paths["/calendars/{calendarId}"]["get"]
|
502
|
+
assert get_calendar["operationId"] == "calendar.calendars.get"
|
503
|
+
assert "parameters" in get_calendar
|
504
|
+
|
505
|
+
# Verify request body
|
506
|
+
insert_calendar = paths["/calendars"]["post"]
|
507
|
+
assert "requestBody" in insert_calendar
|
508
|
+
request_schema = insert_calendar["requestBody"]["content"][
|
509
|
+
"application/json"
|
510
|
+
]["schema"]
|
511
|
+
assert request_schema["$ref"] == "#/components/schemas/Calendar"
|
512
|
+
|
513
|
+
# Verify response body
|
514
|
+
assert "responses" in get_calendar
|
515
|
+
response_schema = get_calendar["responses"]["200"]["content"][
|
516
|
+
"application/json"
|
517
|
+
]["schema"]
|
518
|
+
assert response_schema["$ref"] == "#/components/schemas/Calendar"
|
519
|
+
|
520
|
+
def test_convert_methods(self, prepared_converter, calendar_api_spec):
|
521
|
+
"""Test conversion of API methods."""
|
522
|
+
# Convert methods
|
523
|
+
methods = calendar_api_spec["resources"]["calendars"]["methods"]
|
524
|
+
prepared_converter._convert_methods(methods, "/calendars")
|
525
|
+
|
526
|
+
# Verify the results
|
527
|
+
paths = prepared_converter.openapi_spec["paths"]
|
528
|
+
|
529
|
+
# Check GET method
|
530
|
+
assert "/calendars/{calendarId}" in paths
|
531
|
+
get_method = paths["/calendars/{calendarId}"]["get"]
|
532
|
+
assert get_method["operationId"] == "calendar.calendars.get"
|
533
|
+
|
534
|
+
# Check parameters
|
535
|
+
params = get_method["parameters"]
|
536
|
+
param_names = [p["name"] for p in params]
|
537
|
+
assert "calendarId" in param_names
|
538
|
+
|
539
|
+
# Check POST method
|
540
|
+
assert "/calendars" in paths
|
541
|
+
post_method = paths["/calendars"]["post"]
|
542
|
+
assert post_method["operationId"] == "calendar.calendars.insert"
|
543
|
+
|
544
|
+
# Check request body
|
545
|
+
assert "requestBody" in post_method
|
546
|
+
assert (
|
547
|
+
post_method["requestBody"]["content"]["application/json"]["schema"][
|
548
|
+
"$ref"
|
549
|
+
]
|
550
|
+
== "#/components/schemas/Calendar"
|
551
|
+
)
|
552
|
+
|
553
|
+
# Check response
|
554
|
+
assert (
|
555
|
+
post_method["responses"]["200"]["content"]["application/json"][
|
556
|
+
"schema"
|
557
|
+
]["$ref"]
|
558
|
+
== "#/components/schemas/Calendar"
|
559
|
+
)
|
560
|
+
|
561
|
+
def test_convert_resources(self, prepared_converter, calendar_api_spec):
|
562
|
+
"""Test conversion of nested resources."""
|
563
|
+
# Convert resources
|
564
|
+
resources = calendar_api_spec["resources"]
|
565
|
+
prepared_converter._convert_resources(resources)
|
566
|
+
|
567
|
+
# Verify the results
|
568
|
+
paths = prepared_converter.openapi_spec["paths"]
|
569
|
+
|
570
|
+
# Check top-level resource methods
|
571
|
+
assert "/calendars/{calendarId}" in paths
|
572
|
+
|
573
|
+
# Check nested resource methods
|
574
|
+
assert "/calendars/{calendarId}/events" in paths
|
575
|
+
events_method = paths["/calendars/{calendarId}/events"]["get"]
|
576
|
+
assert events_method["operationId"] == "calendar.events.list"
|
577
|
+
|
578
|
+
# Check parameters in nested resource
|
579
|
+
params = events_method["parameters"]
|
580
|
+
param_names = [p["name"] for p in params]
|
581
|
+
assert "calendarId" in param_names
|
582
|
+
assert "maxResults" in param_names
|
583
|
+
assert "orderBy" in param_names
|
584
|
+
|
585
|
+
def test_integration_calendar_api(self, converter_with_patched_build):
|
586
|
+
"""Integration test using Calendar API specification."""
|
587
|
+
# Create and run the converter
|
588
|
+
openapi_spec = converter_with_patched_build.convert()
|
589
|
+
|
590
|
+
# Verify conversion results
|
591
|
+
assert openapi_spec["info"]["title"] == "Google Calendar API"
|
592
|
+
assert (
|
593
|
+
openapi_spec["servers"][0]["url"]
|
594
|
+
== "https://www.googleapis.com/calendar/v3"
|
595
|
+
)
|
596
|
+
|
597
|
+
# Check security schemes
|
598
|
+
security_schemes = openapi_spec["components"]["securitySchemes"]
|
599
|
+
assert "oauth2" in security_schemes
|
600
|
+
assert "apiKey" in security_schemes
|
601
|
+
|
602
|
+
# Check schemas
|
603
|
+
schemas = openapi_spec["components"]["schemas"]
|
604
|
+
assert "Calendar" in schemas
|
605
|
+
assert "Event" in schemas
|
606
|
+
assert "EventDateTime" in schemas
|
607
|
+
|
608
|
+
# Check paths
|
609
|
+
paths = openapi_spec["paths"]
|
610
|
+
assert "/calendars/{calendarId}" in paths
|
611
|
+
assert "/calendars" in paths
|
612
|
+
assert "/calendars/{calendarId}/events" in paths
|
613
|
+
|
614
|
+
# Check method details
|
615
|
+
get_events = paths["/calendars/{calendarId}/events"]["get"]
|
616
|
+
assert get_events["operationId"] == "calendar.events.list"
|
617
|
+
|
618
|
+
# Check parameter details
|
619
|
+
param_dict = {p["name"]: p for p in get_events["parameters"]}
|
620
|
+
assert "maxResults" in param_dict
|
621
|
+
max_results = param_dict["maxResults"]
|
622
|
+
assert max_results["in"] == "query"
|
623
|
+
assert max_results["schema"]["type"] == "integer"
|
624
|
+
assert max_results["schema"]["default"] == "250"
|
625
|
+
|
626
|
+
|
627
|
+
@pytest.fixture
|
628
|
+
def conftest_content():
|
629
|
+
"""Returns content for a conftest.py file to help with testing."""
|
630
|
+
return """
|
631
|
+
import pytest
|
632
|
+
from unittest.mock import MagicMock
|
633
|
+
|
634
|
+
# This file contains fixtures that can be shared across multiple test modules
|
635
|
+
|
636
|
+
@pytest.fixture
|
637
|
+
def mock_google_response():
|
638
|
+
\"\"\"Fixture that provides a mock response from Google's API.\"\"\"
|
639
|
+
return {"key": "value", "items": [{"id": 1}, {"id": 2}]}
|
640
|
+
|
641
|
+
@pytest.fixture
|
642
|
+
def mock_http_error():
|
643
|
+
\"\"\"Fixture that provides a mock HTTP error.\"\"\"
|
644
|
+
mock_resp = MagicMock()
|
645
|
+
mock_resp.status = 404
|
646
|
+
return HttpError(resp=mock_resp, content=b'Not Found')
|
647
|
+
"""
|
648
|
+
|
649
|
+
|
650
|
+
def test_generate_conftest_example(conftest_content):
|
651
|
+
"""This is a meta-test that demonstrates how to generate a conftest.py file.
|
652
|
+
|
653
|
+
In a real project, you would create a separate conftest.py file.
|
654
|
+
"""
|
655
|
+
# In a real scenario, you would write this to a file named conftest.py
|
656
|
+
# This test just verifies the conftest content is not empty
|
657
|
+
assert len(conftest_content) > 0
|