This is page 501 of 503. Use http://codebase.md/awslabs/mcp?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .devcontainer
│ └── devcontainer.json
├── .github
│ ├── actions
│ │ ├── build-and-push-container-image
│ │ │ └── action.yml
│ │ └── clear-space-ubuntu-latest-agressively
│ │ └── action.yml
│ ├── codecov.yml
│ ├── CODEOWNERS
│ ├── dependabot.yml
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.yml
│ │ ├── documentation.yml
│ │ ├── feature_request.yml
│ │ ├── rfc.yml
│ │ └── support_awslabs_mcp_servers.yml
│ ├── pull_request_template.md
│ ├── SECURITY
│ ├── SUPPORT
│ └── workflows
│ ├── aws-api-mcp-upgrade-version.yml
│ ├── bandit-requirements.txt
│ ├── bandit.yml
│ ├── cfn_nag.yml
│ ├── check-gh-pages-builds.yml
│ ├── check-license-header-hash.txt
│ ├── check-license-header.json
│ ├── check-license-header.yml
│ ├── checkov.yml
│ ├── codeql.yml
│ ├── dependency-review-action.yml
│ ├── detect-secrets-requirements.txt
│ ├── gh-pages.yml
│ ├── merge-prevention.yml
│ ├── powershell.yml
│ ├── pre-commit-requirements.txt
│ ├── pre-commit.yml
│ ├── pull-request-lint.yml
│ ├── python.yml
│ ├── RELEASE_INSTRUCTIONS.md
│ ├── release-initiate-branch.yml
│ ├── release-merge-tag.yml
│ ├── release.py
│ ├── release.yml
│ ├── scanners.yml
│ ├── scorecard-analysis.yml
│ ├── semgrep-requirements.txt
│ ├── semgrep.yml
│ ├── stale.yml
│ ├── trivy.yml
│ └── typescript.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── .ruff.toml
├── .secrets.baseline
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DESIGN_GUIDELINES.md
├── DEVELOPER_GUIDE.md
├── docs
│ └── images
│ └── root-readme
│ ├── cline-api-provider-filled.png
│ ├── cline-chat-interface.png
│ ├── cline-custom-instructions.png
│ ├── cline-select-aws-profile.png
│ ├── cline-select-bedrock.png
│ ├── configure-mcp-servers.png
│ ├── install-cline-extension.png
│ ├── mcp-servers-installed.png
│ └── select-mcp-servers.png
├── docusaurus
│ ├── .gitignore
│ ├── docs
│ │ ├── installation.md
│ │ ├── intro.md
│ │ ├── samples
│ │ │ ├── index.md
│ │ │ ├── mcp-integration-with-kb.md
│ │ │ ├── mcp-integration-with-nova-canvas.md
│ │ │ └── stepfunctions-tool-mcp-server.md
│ │ ├── servers
│ │ │ ├── amazon-bedrock-agentcore-mcp-server.md
│ │ │ ├── amazon-keyspaces-mcp-server.md
│ │ │ ├── amazon-mq-mcp-server.md
│ │ │ ├── amazon-neptune-mcp-server.md
│ │ │ ├── amazon-qbusiness-anonymous-mcp-server.md
│ │ │ ├── amazon-qindex-mcp-server.md
│ │ │ ├── amazon-sns-sqs-mcp-server.md
│ │ │ ├── aurora-dsql-mcp-server.md
│ │ │ ├── aws-api-mcp-server.md
│ │ │ ├── aws-appsync-mcp-server.md
│ │ │ ├── aws-bedrock-custom-model-import-mcp-server.md
│ │ │ ├── aws-bedrock-data-automation-mcp-server.md
│ │ │ ├── aws-dataprocessing-mcp-server.md
│ │ │ ├── aws-diagram-mcp-server.md
│ │ │ ├── aws-documentation-mcp-server.md
│ │ │ ├── aws-healthomics-mcp-server.md
│ │ │ ├── aws-iot-sitewise-mcp-server.md
│ │ │ ├── aws-knowledge-mcp-server.md
│ │ │ ├── aws-location-mcp-server.md
│ │ │ ├── aws-msk-mcp-server.md
│ │ │ ├── aws-pricing-mcp-server.md
│ │ │ ├── aws-serverless-mcp-server.md
│ │ │ ├── aws-support-mcp-server.md
│ │ │ ├── bedrock-kb-retrieval-mcp-server.md
│ │ │ ├── billing-cost-management-mcp-server.md
│ │ │ ├── ccapi-mcp-server.md
│ │ │ ├── cdk-mcp-server.md
│ │ │ ├── cfn-mcp-server.md
│ │ │ ├── cloudtrail-mcp-server.md
│ │ │ ├── cloudwatch-appsignals-mcp-server.md
│ │ │ ├── cloudwatch-mcp-server.md
│ │ │ ├── code-doc-gen-mcp-server.md
│ │ │ ├── core-mcp-server.md
│ │ │ ├── cost-explorer-mcp-server.md
│ │ │ ├── documentdb-mcp-server.md
│ │ │ ├── dynamodb-mcp-server.md
│ │ │ ├── ecs-mcp-server.md
│ │ │ ├── eks-mcp-server.md
│ │ │ ├── elasticache-mcp-server.md
│ │ │ ├── finch-mcp-server.md
│ │ │ ├── frontend-mcp-server.md
│ │ │ ├── git-repo-research-mcp-server.md
│ │ │ ├── healthlake-mcp-server.md
│ │ │ ├── iam-mcp-server.md
│ │ │ ├── kendra-index-mcp-server.md
│ │ │ ├── lambda-tool-mcp-server.md
│ │ │ ├── memcached-mcp-server.md
│ │ │ ├── mysql-mcp-server.md
│ │ │ ├── nova-canvas-mcp-server.md
│ │ │ ├── openapi-mcp-server.md
│ │ │ ├── postgres-mcp-server.md
│ │ │ ├── prometheus-mcp-server.md
│ │ │ ├── redshift-mcp-server.md
│ │ │ ├── s3-tables-mcp-server.md
│ │ │ ├── stepfunctions-tool-mcp-server.md
│ │ │ ├── syntheticdata-mcp-server.md
│ │ │ ├── terraform-mcp-server.md
│ │ │ ├── timestream-for-influxdb-mcp-server.md
│ │ │ ├── valkey-mcp-server.md
│ │ │ └── well-architected-security-mcp-server.mdx
│ │ └── vibe_coding.md
│ ├── docusaurus.config.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── sidebars.ts
│ ├── src
│ │ ├── components
│ │ │ ├── HomepageFeatures
│ │ │ │ └── styles.module.css
│ │ │ └── ServerCards
│ │ │ ├── index.tsx
│ │ │ └── styles.module.css
│ │ ├── css
│ │ │ ├── custom.css
│ │ │ └── doc-override.css
│ │ └── pages
│ │ ├── index.module.css
│ │ └── servers.tsx
│ ├── static
│ │ ├── .nojekyll
│ │ ├── assets
│ │ │ ├── icons
│ │ │ │ ├── activity.svg
│ │ │ │ ├── book-open.svg
│ │ │ │ ├── cpu.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── dollar-sign.svg
│ │ │ │ ├── help-circle.svg
│ │ │ │ ├── key.svg
│ │ │ │ ├── server.svg
│ │ │ │ ├── share-2.svg
│ │ │ │ ├── tool.svg
│ │ │ │ └── zap.svg
│ │ │ └── server-cards.json
│ │ └── img
│ │ ├── aws-logo.svg
│ │ └── logo.png
│ └── tsconfig.json
├── LICENSE
├── NOTICE
├── README.md
├── samples
│ ├── mcp-integration-with-kb
│ │ ├── .env.example
│ │ ├── .python-version
│ │ ├── assets
│ │ │ └── simplified-mcp-flow-diagram.png
│ │ ├── clients
│ │ │ └── client_server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── user_interfaces
│ │ │ └── chat_bedrock_st.py
│ │ └── uv.lock
│ ├── mcp-integration-with-nova-canvas
│ │ ├── .env.example
│ │ ├── .python-version
│ │ ├── clients
│ │ │ └── client_server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── user_interfaces
│ │ │ └── image_generator_st.py
│ │ └── uv.lock
│ ├── README.md
│ └── stepfunctions-tool-mcp-server
│ ├── README.md
│ └── sample_state_machines
│ ├── customer-create
│ │ └── app.py
│ ├── customer-id-from-email
│ │ └── app.py
│ ├── customer-info-from-id
│ │ └── app.py
│ └── template.yml
├── src
│ ├── amazon-bedrock-agentcore-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_bedrock_agentcore_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── config.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── cache.py
│ │ │ ├── doc_fetcher.py
│ │ │ ├── indexer.py
│ │ │ ├── text_processor.py
│ │ │ └── url_validator.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_cache.py
│ │ │ ├── test_config.py
│ │ │ ├── test_doc_fetcher.py
│ │ │ ├── test_indexer.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_server.py
│ │ │ ├── test_text_processor.py
│ │ │ └── test_url_validator.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-kendra-index-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_kendra_index_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── util.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-keyspaces-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_keyspaces_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── config.py
│ │ │ ├── consts.py
│ │ │ ├── llm_context.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── services.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_client.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_query_analysis_service.py
│ │ │ ├── test_server.py
│ │ │ └── test_services.py
│ │ └── uv.lock
│ ├── amazon-mq-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_mq_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_service_mcp_generator.py
│ │ │ ├── consts.py
│ │ │ ├── rabbitmq
│ │ │ │ ├── __init__.py
│ │ │ │ ├── admin.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── doc
│ │ │ │ │ ├── rabbitmq_broker_sizing_guide.md
│ │ │ │ │ ├── rabbitmq_performance_optimization_best_practice.md
│ │ │ │ │ ├── rabbitmq_production_deployment_guidelines.md
│ │ │ │ │ ├── rabbitmq_quorum_queue_migration_guide.md
│ │ │ │ │ └── rabbitmq_setup_best_practice.md
│ │ │ │ ├── handlers.py
│ │ │ │ └── module.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── example
│ │ │ └── sample_mcp_q_cli.json
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── rabbitmq
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_admin.py
│ │ │ │ ├── test_connection.py
│ │ │ │ ├── test_handlers.py
│ │ │ │ └── test_module.py
│ │ │ ├── test_aws_service_mcp_generator.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-neptune-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_neptune_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── graph_store
│ │ │ │ ├── __init__.py
│ │ │ │ ├── analytics.py
│ │ │ │ ├── base.py
│ │ │ │ └── database.py
│ │ │ ├── models.py
│ │ │ ├── neptune.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_analytics.py
│ │ │ ├── test_database.py
│ │ │ ├── test_exceptions.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_neptune.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-qbusiness-anonymous-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_qbusiness_anonymous_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── clients.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-qindex-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_qindex_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── clients.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_clients.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ └── uv.lock
│ ├── amazon-sns-sqs-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_sns_sqs_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── consts.py
│ │ │ ├── generator.py
│ │ │ ├── server.py
│ │ │ ├── sns.py
│ │ │ └── sqs.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── print_tools.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── test_common.py
│ │ │ ├── test_generator.py
│ │ │ ├── test_server.py
│ │ │ ├── test_sns.py
│ │ │ └── test_sqs.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aurora-dsql-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aurora_dsql_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_connection_reuse.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_profile_option.py
│ │ │ ├── test_readonly_enforcement.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-api-mcp-server
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_api_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_scripts
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── manager.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ └── registry
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── application-failure-troubleshooting.script.md
│ │ │ │ │ ├── cloudtral-mutli-region-setup.script.md
│ │ │ │ │ ├── create_amazon_aurora_db_cluster_with_instances.script.md
│ │ │ │ │ ├── lambda-timeout-debugging.script.md
│ │ │ │ │ ├── scripts_format.md
│ │ │ │ │ └── troubleshoot-permissions-with-cloudtrail-events.script.md
│ │ │ │ ├── aws
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── driver.py
│ │ │ │ │ ├── pagination.py
│ │ │ │ │ ├── regions.py
│ │ │ │ │ ├── service.py
│ │ │ │ │ └── services.py
│ │ │ │ ├── common
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── command_metadata.py
│ │ │ │ │ ├── command.py
│ │ │ │ │ ├── config.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_operations.py
│ │ │ │ │ ├── file_system_controls.py
│ │ │ │ │ ├── helpers.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── data
│ │ │ │ │ └── api_metadata.json
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── read_only_operations_list.py
│ │ │ │ ├── parser
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── custom_validators
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── botocore_param_validator.py
│ │ │ │ │ │ ├── ec2_validator.py
│ │ │ │ │ │ └── ssm_validator.py
│ │ │ │ │ ├── interpretation.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ └── parser.py
│ │ │ │ ├── py.typed
│ │ │ │ └── security
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_api_customization.json
│ │ │ │ └── policy.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── agent_scripts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_manager.py
│ │ │ │ └── test_registry
│ │ │ │ ├── another_valid_script.script.md
│ │ │ │ ├── test_script.script.md
│ │ │ │ └── valid_script.script.md
│ │ │ ├── aws
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_driver.py
│ │ │ │ ├── test_pagination.py
│ │ │ │ ├── test_service.py
│ │ │ │ └── test_services.py
│ │ │ ├── common
│ │ │ │ ├── test_command.py
│ │ │ │ ├── test_config.py
│ │ │ │ ├── test_file_operations.py
│ │ │ │ ├── test_file_system_controls.py
│ │ │ │ ├── test_file_validation.py
│ │ │ │ └── test_helpers.py
│ │ │ ├── fixtures.py
│ │ │ ├── history_handler.py
│ │ │ ├── metadata
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_read_only_operations_list.py
│ │ │ ├── parser
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_file_path_detection.py
│ │ │ │ ├── test_lexer.py
│ │ │ │ ├── test_parser_customizations.py
│ │ │ │ └── test_parser.py
│ │ │ ├── test_security_policy.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-appsync-mcp-server
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_appsync_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── decorators.py
│ │ │ ├── helpers.py
│ │ │ ├── operations
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_api_cache.py
│ │ │ │ ├── create_api_key.py
│ │ │ │ ├── create_api.py
│ │ │ │ ├── create_channel_namespace.py
│ │ │ │ ├── create_datasource.py
│ │ │ │ ├── create_domain_name.py
│ │ │ │ ├── create_function.py
│ │ │ │ ├── create_graphql_api.py
│ │ │ │ ├── create_resolver.py
│ │ │ │ └── create_schema.py
│ │ │ ├── server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_api_cache.py
│ │ │ │ ├── create_api_key.py
│ │ │ │ ├── create_api.py
│ │ │ │ ├── create_channel_namespace.py
│ │ │ │ ├── create_datasource.py
│ │ │ │ ├── create_domain_name.py
│ │ │ │ ├── create_function.py
│ │ │ │ ├── create_graphql_api.py
│ │ │ │ ├── create_resolver.py
│ │ │ │ └── create_schema.py
│ │ │ └── validators.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_all_create_tools_write_protection.py
│ │ │ ├── test_create_api_cache.py
│ │ │ ├── test_create_api_key.py
│ │ │ ├── test_create_api.py
│ │ │ ├── test_create_channel_namespace.py
│ │ │ ├── test_create_datasource_tool.py
│ │ │ ├── test_create_datasource.py
│ │ │ ├── test_create_domain_name.py
│ │ │ ├── test_create_function.py
│ │ │ ├── test_create_graphql_api.py
│ │ │ ├── test_create_resolver.py
│ │ │ ├── test_create_schema_tool.py
│ │ │ ├── test_create_schema.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_server.py
│ │ │ ├── test_validators.py
│ │ │ └── test_write_operation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-bedrock-custom-model-import-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_bedrock_custom_model_import_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── llm_context.py
│ │ │ ├── models.py
│ │ │ ├── prompts.py
│ │ │ ├── server.py
│ │ │ ├── services
│ │ │ │ ├── __init__.py
│ │ │ │ ├── imported_model_service.py
│ │ │ │ └── model_import_service.py
│ │ │ ├── tools
│ │ │ │ ├── create_model_import_job.py
│ │ │ │ ├── delete_imported_model.py
│ │ │ │ ├── get_imported_model.py
│ │ │ │ ├── get_model_import_job.py
│ │ │ │ ├── list_imported_models.py
│ │ │ │ └── list_model_import_jobs.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws.py
│ │ │ ├── config.py
│ │ │ ├── consts.py
│ │ │ └── matching.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── services
│ │ │ │ ├── test_imported_model_service.py
│ │ │ │ └── test_model_import_service.py
│ │ │ ├── test_client.py
│ │ │ ├── test_init.py
│ │ │ ├── test_llm_context.py
│ │ │ ├── test_prompts.py
│ │ │ ├── test_server.py
│ │ │ ├── tools
│ │ │ │ ├── test_create_model_import_job.py
│ │ │ │ ├── test_delete_imported_model.py
│ │ │ │ ├── test_get_imported_model.py
│ │ │ │ ├── test_get_model_import_job.py
│ │ │ │ ├── test_list_imported_models.py
│ │ │ │ └── test_list_model_import_jobs.py
│ │ │ └── utils
│ │ │ ├── test_aws.py
│ │ │ ├── test_config.py
│ │ │ └── test_matching.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-bedrock-data-automation-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_bedrock_data_automation_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── helpers.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-dataprocessing-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_dataprocessing_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ └── glue_data_catalog
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_catalog_database_manager.py
│ │ │ │ ├── data_catalog_handler.py
│ │ │ │ └── data_catalog_table_manager.py
│ │ │ ├── handlers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── athena_data_catalog_handler.py
│ │ │ │ │ ├── athena_query_handler.py
│ │ │ │ │ └── athena_workgroup_handler.py
│ │ │ │ ├── commons
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── common_resource_handler.py
│ │ │ │ ├── emr
│ │ │ │ │ ├── emr_ec2_cluster_handler.py
│ │ │ │ │ ├── emr_ec2_instance_handler.py
│ │ │ │ │ └── emr_ec2_steps_handler.py
│ │ │ │ └── glue
│ │ │ │ ├── __init__.py
│ │ │ │ ├── crawler_handler.py
│ │ │ │ ├── data_catalog_handler.py
│ │ │ │ ├── glue_commons_handler.py
│ │ │ │ ├── glue_etl_handler.py
│ │ │ │ ├── interactive_sessions_handler.py
│ │ │ │ └── worklows_handler.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena_models.py
│ │ │ │ ├── common_resource_models.py
│ │ │ │ ├── data_catalog_models.py
│ │ │ │ ├── emr_models.py
│ │ │ │ └── glue_models.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ ├── consts.py
│ │ │ ├── logging_helper.py
│ │ │ └── mutable_sql_detector.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ └── glue_data_catalog
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_data_catalog_database_manager.py
│ │ │ │ ├── test_data_catalog_handler.py
│ │ │ │ └── test_data_catalog_table_manager.py
│ │ │ ├── handlers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_athena_data_catalog_handler.py
│ │ │ │ │ ├── test_athena_query_handler.py
│ │ │ │ │ ├── test_athena_workgroup_handler.py
│ │ │ │ │ └── test_custom_tags_athena.py
│ │ │ │ ├── commons
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_common_resource_handler.py
│ │ │ │ ├── emr
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_custom_tags_emr.py
│ │ │ │ │ ├── test_emr_ec2_cluster_handler.py
│ │ │ │ │ ├── test_emr_ec2_instance_handler.py
│ │ │ │ │ └── test_emr_ec2_steps_handler.py
│ │ │ │ └── glue
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_crawler_handler.py
│ │ │ │ ├── test_custom_tags_glue.py
│ │ │ │ ├── test_data_catalog_handler.py
│ │ │ │ ├── test_glue_commons_handler.py
│ │ │ │ ├── test_glue_etl_handler.py
│ │ │ │ ├── test_glue_interactive_sessions_handler.py
│ │ │ │ └── test_glue_workflows_handler.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_athena_models.py
│ │ │ │ ├── test_common_resource_models.py
│ │ │ │ ├── test_data_catalog_models.py
│ │ │ │ ├── test_emr_models.py
│ │ │ │ ├── test_glue_models.py
│ │ │ │ ├── test_interactive_sessions_models.py
│ │ │ │ └── test_workflows_models.py
│ │ │ ├── test_init.py
│ │ │ ├── test_server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_custom_tags.py
│ │ │ └── test_logging_helper.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-diagram-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_diagram_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── diagrams_tools.py
│ │ │ ├── models.py
│ │ │ ├── scanner.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── resources
│ │ │ │ ├── __init__.py
│ │ │ │ └── example_diagrams
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_example.py
│ │ │ │ ├── flow_example.py
│ │ │ │ └── sequence_example.py
│ │ │ ├── test_diagrams.py
│ │ │ ├── test_models.py
│ │ │ ├── test_sarif_fix.py
│ │ │ ├── test_scanner.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-documentation-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_documentation_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── server_aws_cn.py
│ │ │ ├── server_aws.py
│ │ │ ├── server_utils.py
│ │ │ ├── server.py
│ │ │ └── util.py
│ │ ├── basic-usage.gif
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── constants.py
│ │ │ ├── resources
│ │ │ │ └── lambda_sns_raw.html
│ │ │ ├── test_aws_cn_get_available_services_live.py
│ │ │ ├── test_aws_cn_read_documentation_live.py
│ │ │ ├── test_aws_read_documentation_live.py
│ │ │ ├── test_aws_recommend_live.py
│ │ │ ├── test_aws_search_live.py
│ │ │ ├── test_metadata_handling.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server_aws_cn.py
│ │ │ ├── test_server_aws.py
│ │ │ ├── test_server_utils.py
│ │ │ ├── test_server.py
│ │ │ └── test_util.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-healthomics-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_healthomics_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── helper_tools.py
│ │ │ │ ├── run_analysis.py
│ │ │ │ ├── troubleshooting.py
│ │ │ │ ├── workflow_analysis.py
│ │ │ │ ├── workflow_execution.py
│ │ │ │ ├── workflow_linting.py
│ │ │ │ └── workflow_management.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws_utils.py
│ │ │ ├── s3_utils.py
│ │ │ └── validation_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── docs
│ │ │ └── workflow_linting.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_aws_utils.py
│ │ │ ├── test_consts.py
│ │ │ ├── test_helper_tools.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_run_analysis.py
│ │ │ ├── test_s3_utils.py
│ │ │ ├── test_server.py
│ │ │ ├── test_troubleshooting.py
│ │ │ ├── test_workflow_analysis.py
│ │ │ ├── test_workflow_execution.py
│ │ │ ├── test_workflow_linting.py
│ │ │ ├── test_workflow_management.py
│ │ │ └── test_workflow_tools.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-iot-sitewise-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_iot_sitewise_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── asset_hierarchy.py
│ │ │ │ ├── data_exploration.py
│ │ │ │ └── data_ingestion.py
│ │ │ ├── server.py
│ │ │ ├── tool_metadata.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── sitewise_access.py
│ │ │ │ ├── sitewise_asset_models.py
│ │ │ │ ├── sitewise_assets.py
│ │ │ │ ├── sitewise_data.py
│ │ │ │ └── sitewise_gateways.py
│ │ │ └── validation.py
│ │ ├── CHANGELOG.md
│ │ ├── DEVELOPMENT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ └── wind_farm_example.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_server.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_server.py
│ │ │ ├── test_sitewise_access.py
│ │ │ ├── test_sitewise_asset_models.py
│ │ │ ├── test_sitewise_assets.py
│ │ │ ├── test_sitewise_data.py
│ │ │ ├── test_sitewise_gateways.py
│ │ │ └── test_validation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-knowledge-mcp-server
│ │ └── README.md
│ ├── aws-location-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_location_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_server_integration.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-msk-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_msk_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── tools
│ │ │ ├── __init__.py
│ │ │ ├── common_functions
│ │ │ │ ├── __init__.py
│ │ │ │ ├── client_manager.py
│ │ │ │ └── common_functions.py
│ │ │ ├── logs_and_telemetry
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cluster_metrics_tools.py
│ │ │ │ ├── list_customer_iam_access.py
│ │ │ │ └── metric_config.py
│ │ │ ├── mutate_cluster
│ │ │ │ ├── __init__.py
│ │ │ │ ├── batch_associate_scram_secret.py
│ │ │ │ ├── batch_disassociate_scram_secret.py
│ │ │ │ ├── create_cluster_v2.py
│ │ │ │ ├── put_cluster_policy.py
│ │ │ │ ├── reboot_broker.py
│ │ │ │ ├── update_broker_count.py
│ │ │ │ ├── update_broker_storage.py
│ │ │ │ ├── update_broker_type.py
│ │ │ │ ├── update_cluster_configuration.py
│ │ │ │ ├── update_monitoring.py
│ │ │ │ └── update_security.py
│ │ │ ├── mutate_config
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_configuration.py
│ │ │ │ ├── tag_resource.py
│ │ │ │ ├── untag_resource.py
│ │ │ │ └── update_configuration.py
│ │ │ ├── mutate_vpc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_vpc_connection.py
│ │ │ │ ├── delete_vpc_connection.py
│ │ │ │ └── reject_client_vpc_connection.py
│ │ │ ├── read_cluster
│ │ │ │ ├── __init__.py
│ │ │ │ ├── describe_cluster_operation.py
│ │ │ │ ├── describe_cluster.py
│ │ │ │ ├── get_bootstrap_brokers.py
│ │ │ │ ├── get_cluster_policy.py
│ │ │ │ ├── get_compatible_kafka_versions.py
│ │ │ │ ├── list_client_vpc_connections.py
│ │ │ │ ├── list_cluster_operations.py
│ │ │ │ ├── list_nodes.py
│ │ │ │ └── list_scram_secrets.py
│ │ │ ├── read_config
│ │ │ │ ├── __init__.py
│ │ │ │ ├── describe_configuration_revision.py
│ │ │ │ ├── describe_configuration.py
│ │ │ │ ├── list_configuration_revisions.py
│ │ │ │ └── list_tags_for_resource.py
│ │ │ ├── read_global
│ │ │ │ ├── __init__.py
│ │ │ │ ├── list_clusters.py
│ │ │ │ ├── list_configurations.py
│ │ │ │ ├── list_kafka_versions.py
│ │ │ │ └── list_vpc_connections.py
│ │ │ ├── read_vpc
│ │ │ │ ├── __init__.py
│ │ │ │ └── describe_vpc_connection.py
│ │ │ └── static_tools
│ │ │ ├── __init__.py
│ │ │ └── cluster_best_practices.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_client_manager.py
│ │ │ ├── test_cluster_metrics_tools.py
│ │ │ ├── test_common_functions.py
│ │ │ ├── test_create_cluster_v2.py
│ │ │ ├── test_create_configuration.py
│ │ │ ├── test_create_vpc_connection.py
│ │ │ ├── test_delete_vpc_connection.py
│ │ │ ├── test_describe_cluster_operation.py
│ │ │ ├── test_describe_cluster.py
│ │ │ ├── test_describe_configuration_revision.py
│ │ │ ├── test_describe_configuration.py
│ │ │ ├── test_describe_vpc_connection.py
│ │ │ ├── test_get_bootstrap_brokers.py
│ │ │ ├── test_get_cluster_policy.py
│ │ │ ├── test_get_compatible_kafka_versions.py
│ │ │ ├── test_init.py
│ │ │ ├── test_list_client_vpc_connections.py
│ │ │ ├── test_list_cluster_operations.py
│ │ │ ├── test_list_clusters.py
│ │ │ ├── test_list_configuration_revisions.py
│ │ │ ├── test_list_configurations.py
│ │ │ ├── test_list_customer_iam_access.py
│ │ │ ├── test_list_kafka_versions.py
│ │ │ ├── test_list_nodes.py
│ │ │ ├── test_list_scram_secrets.py
│ │ │ ├── test_list_tags_for_resource.py
│ │ │ ├── test_list_vpc_connections.py
│ │ │ ├── test_logs_and_telemetry.py
│ │ │ ├── test_main.py
│ │ │ ├── test_mutate_cluster_init.py
│ │ │ ├── test_mutate_cluster_success_cases.py
│ │ │ ├── test_mutate_cluster.py
│ │ │ ├── test_mutate_config_init.py
│ │ │ ├── test_mutate_vpc_init.py
│ │ │ ├── test_read_cluster_init_updated.py
│ │ │ ├── test_read_cluster_init.py
│ │ │ ├── test_read_config_init.py
│ │ │ ├── test_read_global_init.py
│ │ │ ├── test_read_vpc_init.py
│ │ │ ├── test_reject_client_vpc_connection.py
│ │ │ ├── test_server.py
│ │ │ ├── test_static_tools_init.py
│ │ │ ├── test_tag_resource.py
│ │ │ ├── test_tool_descriptions.py
│ │ │ ├── test_untag_resource.py
│ │ │ └── test_update_configuration.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-pricing-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_pricing_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── cdk_analyzer.py
│ │ │ ├── consts.py
│ │ │ ├── helpers.py
│ │ │ ├── models.py
│ │ │ ├── pricing_client.py
│ │ │ ├── pricing_transformer.py
│ │ │ ├── report_generator.py
│ │ │ ├── server.py
│ │ │ ├── static
│ │ │ │ ├── __init__.py
│ │ │ │ ├── COST_REPORT_TEMPLATE.md
│ │ │ │ └── patterns
│ │ │ │ ├── __init__.py
│ │ │ │ └── BEDROCK.md
│ │ │ └── terraform_analyzer.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_cdk_analyzer.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_pricing_client.py
│ │ │ ├── test_pricing_transformer.py
│ │ │ ├── test_report_generator.py
│ │ │ ├── test_server.py
│ │ │ └── test_terraform_analyzer.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-serverless-mcp-server
│ │ ├── .pre-commit.config.yaml
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_serverless_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── resources
│ │ │ │ ├── __init__.py
│ │ │ │ ├── deployment_details.py
│ │ │ │ ├── deployment_list.py
│ │ │ │ ├── template_details.py
│ │ │ │ └── template_list.py
│ │ │ ├── server.py
│ │ │ ├── template
│ │ │ │ ├── __init__.py
│ │ │ │ ├── registry.py
│ │ │ │ ├── renderer.py
│ │ │ │ └── templates
│ │ │ │ ├── backend.j2
│ │ │ │ ├── frontend.j2
│ │ │ │ ├── fullstack.j2
│ │ │ │ └── README.md
│ │ │ ├── tools
│ │ │ │ ├── common
│ │ │ │ │ └── base_tool.py
│ │ │ │ ├── guidance
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── deploy_serverless_app_help.py
│ │ │ │ │ ├── get_iac_guidance.py
│ │ │ │ │ ├── get_lambda_event_schemas.py
│ │ │ │ │ ├── get_lambda_guidance.py
│ │ │ │ │ └── get_serverless_templates.py
│ │ │ │ ├── sam
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── sam_build.py
│ │ │ │ │ ├── sam_deploy.py
│ │ │ │ │ ├── sam_init.py
│ │ │ │ │ ├── sam_local_invoke.py
│ │ │ │ │ └── sam_logs.py
│ │ │ │ ├── schemas
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── describe_schema.py
│ │ │ │ │ ├── list_registries.py
│ │ │ │ │ └── search_schema.py
│ │ │ │ └── webapps
│ │ │ │ ├── __init__.py
│ │ │ │ ├── configure_domain.py
│ │ │ │ ├── deploy_webapp.py
│ │ │ │ ├── get_metrics.py
│ │ │ │ ├── update_webapp_frontend.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── deploy_service.py
│ │ │ │ │ ├── frontend_uploader.py
│ │ │ │ │ └── startup_script_generator.py
│ │ │ │ └── webapp_deployment_help.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws_client_helper.py
│ │ │ ├── cloudformation.py
│ │ │ ├── const.py
│ │ │ ├── deployment_manager.py
│ │ │ ├── github.py
│ │ │ └── process.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_cloudformation.py
│ │ │ ├── test_configure_domain.py
│ │ │ ├── test_deploy_serverless_app_help.py
│ │ │ ├── test_deploy_service.py
│ │ │ ├── test_deploy_webapp.py
│ │ │ ├── test_deployment_details.py
│ │ │ ├── test_deployment_help.py
│ │ │ ├── test_deployment_list.py
│ │ │ ├── test_deployment_manager.py
│ │ │ ├── test_frontend_uploader.py
│ │ │ ├── test_get_iac_guidance.py
│ │ │ ├── test_get_lambda_event_schemas.py
│ │ │ ├── test_get_lambda_guidance.py
│ │ │ ├── test_get_metrics.py
│ │ │ ├── test_get_serverless_templates.py
│ │ │ ├── test_github.py
│ │ │ ├── test_models.py
│ │ │ ├── test_process.py
│ │ │ ├── test_sam_build.py
│ │ │ ├── test_sam_deploy.py
│ │ │ ├── test_sam_init.py
│ │ │ ├── test_sam_local_invoke.py
│ │ │ ├── test_sam_logs.py
│ │ │ ├── test_schemas.py
│ │ │ ├── test_server.py
│ │ │ ├── test_startup_script_generator.py
│ │ │ ├── test_template_details.py
│ │ │ ├── test_template_list.py
│ │ │ ├── test_template_registry.py
│ │ │ ├── test_template_renderer.py
│ │ │ └── test_update_webapp_frontend.py
│ │ └── uv.lock
│ ├── aws-support-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_support_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── consts.py
│ │ │ ├── debug_helper.py
│ │ │ ├── errors.py
│ │ │ ├── formatters.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftests.py
│ │ │ ├── test_aws_support_mcp_server.py
│ │ │ └── test_models.py
│ │ └── uv.lock
│ ├── bedrock-kb-retrieval-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── bedrock_kb_retrieval_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── knowledgebases
│ │ │ │ ├── __init__.py
│ │ │ │ ├── clients.py
│ │ │ │ ├── discovery.py
│ │ │ │ └── retrieval.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_clients.py
│ │ │ ├── test_discovery.py
│ │ │ ├── test_env_config.py
│ │ │ ├── test_models.py
│ │ │ ├── test_retrieval.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── billing-cost-management-mcp-server
│ │ ├── __init__.py
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── billing_cost_management_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── decorator.py
│ │ │ │ ├── graviton_migration.py
│ │ │ │ ├── README.md
│ │ │ │ ├── savings_plans.py
│ │ │ │ └── types.py
│ │ │ ├── server.py
│ │ │ ├── templates
│ │ │ │ └── recommendation_templates
│ │ │ │ ├── ebs_volume.template
│ │ │ │ ├── ec2_asg.template
│ │ │ │ ├── ec2_instance.template
│ │ │ │ ├── ecs_service.template
│ │ │ │ ├── idle.template
│ │ │ │ ├── lambda_function.template
│ │ │ │ ├── rds_database.template
│ │ │ │ ├── reserved_instances.template
│ │ │ │ └── savings_plans.template
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_pricing_operations.py
│ │ │ │ ├── aws_pricing_tools.py
│ │ │ │ ├── budget_tools.py
│ │ │ │ ├── compute_optimizer_tools.py
│ │ │ │ ├── cost_anomaly_tools.py
│ │ │ │ ├── cost_comparison_tools.py
│ │ │ │ ├── cost_explorer_operations.py
│ │ │ │ ├── cost_explorer_tools.py
│ │ │ │ ├── cost_optimization_hub_helpers.py
│ │ │ │ ├── cost_optimization_hub_tools.py
│ │ │ │ ├── free_tier_usage_tools.py
│ │ │ │ ├── recommendation_details_tools.py
│ │ │ │ ├── ri_performance_tools.py
│ │ │ │ ├── sp_performance_tools.py
│ │ │ │ ├── storage_lens_tools.py
│ │ │ │ └── unified_sql_tools.py
│ │ │ └── utilities
│ │ │ ├── __init__.py
│ │ │ ├── aws_service_base.py
│ │ │ ├── constants.py
│ │ │ ├── logging_utils.py
│ │ │ └── sql_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_prompts.py
│ │ │ ├── README.md
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixtures.py
│ │ │ │ ├── test_aws_pricing_tools.py
│ │ │ │ ├── test_budget_tools.py
│ │ │ │ ├── test_compute_optimizer_tools.py
│ │ │ │ ├── test_cost_anomaly_tools_enhanced.py
│ │ │ │ ├── test_cost_anomaly_tools.py
│ │ │ │ ├── test_cost_comparison_tools.py
│ │ │ │ ├── test_cost_explorer_operations.py
│ │ │ │ ├── test_cost_explorer_tools.py
│ │ │ │ ├── test_cost_optimization_hub_helpers.py
│ │ │ │ ├── test_cost_optimization_hub_tools.py
│ │ │ │ ├── test_free_tier_usage_tools_new.py
│ │ │ │ ├── test_recommendation_details_tools.py
│ │ │ │ ├── test_ri_performance_tools.py
│ │ │ │ ├── test_sp_performance_tools.py
│ │ │ │ ├── test_storage_lens_tools.py
│ │ │ │ └── test_unified_sql_tools.py
│ │ │ └── utilities
│ │ │ ├── test_aws_service_base.py
│ │ │ └── test_sql_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── ccapi-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── ccapi_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── cloud_control_utils.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── iac_generator.py
│ │ │ ├── impl
│ │ │ │ ├── __init__.py
│ │ │ │ ├── tools
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── explanation.py
│ │ │ │ │ ├── infrastructure_generation.py
│ │ │ │ │ ├── resource_operations.py
│ │ │ │ │ ├── security_scanning.py
│ │ │ │ │ └── session_management.py
│ │ │ │ └── utils
│ │ │ │ ├── __init__.py
│ │ │ │ └── validation.py
│ │ │ ├── infrastructure_generator.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ └── models.py
│ │ │ ├── schema_manager.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ └── __init__.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_client.py
│ │ │ ├── test_checkov_install.py
│ │ │ ├── test_cloud_control_utils.py
│ │ │ ├── test_context.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_explanation.py
│ │ │ ├── test_iac_generator.py
│ │ │ ├── test_infrastructure_generation.py
│ │ │ ├── test_infrastructure_generator.py
│ │ │ ├── test_models.py
│ │ │ ├── test_resource_operations.py
│ │ │ ├── test_schema_manager.py
│ │ │ ├── test_security_scanning.py
│ │ │ ├── test_server.py
│ │ │ ├── test_session_management.py
│ │ │ └── test_validation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cdk-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cdk_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ ├── resources.py
│ │ │ │ ├── search_utils.py
│ │ │ │ ├── server.py
│ │ │ │ └── tools.py
│ │ │ ├── data
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cdk_nag_parser.py
│ │ │ │ ├── construct_descriptions.py
│ │ │ │ ├── genai_cdk_loader.py
│ │ │ │ ├── lambda_layer_parser.py
│ │ │ │ ├── lambda_powertools_loader.py
│ │ │ │ ├── schema_generator.py
│ │ │ │ └── solutions_constructs_parser.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ ├── CDK_GENERAL_GUIDANCE.md
│ │ │ ├── CDK_NAG_GUIDANCE.md
│ │ │ └── lambda_powertools
│ │ │ ├── bedrock.md
│ │ │ ├── cdk.md
│ │ │ ├── dependencies.md
│ │ │ ├── index.md
│ │ │ ├── insights.md
│ │ │ ├── logging.md
│ │ │ ├── metrics.md
│ │ │ └── tracing.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── test_resources_enhanced.py
│ │ │ │ ├── test_resources.py
│ │ │ │ ├── test_search_utils.py
│ │ │ │ ├── test_server.py
│ │ │ │ └── test_tools.py
│ │ │ └── data
│ │ │ ├── test_cdk_nag_parser.py
│ │ │ ├── test_genai_cdk_loader.py
│ │ │ ├── test_lambda_powertools_loader.py
│ │ │ ├── test_schema_generator.py
│ │ │ └── test_solutions_constructs_parser.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cfn-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cfn_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── cloud_control_utils.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── iac_generator.py
│ │ │ ├── schema_manager.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_client.py
│ │ │ ├── test_cloud_control_utils.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_iac_generator.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_schema_manager.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudtrail-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudtrail_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── tools.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_tools.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudwatch-appsignals-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudwatch_appsignals_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── audit_presentation_utils.py
│ │ │ ├── audit_utils.py
│ │ │ ├── aws_clients.py
│ │ │ ├── canary_utils.py
│ │ │ ├── server.py
│ │ │ ├── service_audit_utils.py
│ │ │ ├── service_tools.py
│ │ │ ├── sli_report_client.py
│ │ │ ├── slo_tools.py
│ │ │ ├── trace_tools.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_audit_presentation_utils.py
│ │ │ ├── test_audit_utils.py
│ │ │ ├── test_aws_profile.py
│ │ │ ├── test_canary_utils.py
│ │ │ ├── test_initialization.py
│ │ │ ├── test_server_audit_functions.py
│ │ │ ├── test_server_audit_tools.py
│ │ │ ├── test_server.py
│ │ │ ├── test_service_audit_utils.py
│ │ │ ├── test_service_tools_operations.py
│ │ │ ├── test_sli_report_client.py
│ │ │ ├── test_slo_tools.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudwatch-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudwatch_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── cloudwatch_alarms
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── cloudwatch_logs
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── cloudwatch_metrics
│ │ │ │ ├── data
│ │ │ │ │ └── metric_metadata.json
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── common.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── cloudwatch_alarms
│ │ │ │ ├── test_active_alarms.py
│ │ │ │ ├── test_alarm_history_integration.py
│ │ │ │ ├── test_alarm_history.py
│ │ │ │ └── test_alarms_error_handling.py
│ │ │ ├── cloudwatch_logs
│ │ │ │ ├── test_logs_error_handling.py
│ │ │ │ ├── test_logs_models.py
│ │ │ │ └── test_logs_server.py
│ │ │ ├── cloudwatch_metrics
│ │ │ │ ├── test_metrics_error_handling.py
│ │ │ │ ├── test_metrics_models.py
│ │ │ │ ├── test_metrics_server.py
│ │ │ │ └── test_validation_error.py
│ │ │ ├── test_common_and_server.py
│ │ │ ├── test_init.py
│ │ │ └── test_main.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── code-doc-gen-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── code_doc_gen_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── doc_generator.py
│ │ │ ├── models.py
│ │ │ ├── repomix_manager.py
│ │ │ └── templates.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_doc_generator_edge_cases.py
│ │ │ ├── test_doc_generator.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_repomix_manager_scenarios.py
│ │ │ ├── test_repomix_manager.py
│ │ │ ├── test_repomix_statistics.py
│ │ │ ├── test_server_extended.py
│ │ │ ├── test_server.py
│ │ │ └── test_templates.py
│ │ └── uv.lock
│ ├── core-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── core_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ └── PROMPT_UNDERSTANDING.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_response_types.py
│ │ │ ├── test_server.py
│ │ │ └── test_static.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cost-explorer-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cost_explorer_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── comparison_handler.py
│ │ │ ├── constants.py
│ │ │ ├── cost_usage_handler.py
│ │ │ ├── forecasting_handler.py
│ │ │ ├── helpers.py
│ │ │ ├── metadata_handler.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── utility_handler.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_comparison_handler.py
│ │ │ ├── test_cost_usage_handler.py
│ │ │ ├── test_forecasting_handler.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_metadata_handler.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_utility_handler.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── documentdb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ └── documentdb_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── analytic_tools.py
│ │ │ ├── config.py
│ │ │ ├── connection_tools.py
│ │ │ ├── db_management_tools.py
│ │ │ ├── query_tools.py
│ │ │ ├── server.py
│ │ │ └── write_tools.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_analytic_tools.py
│ │ │ ├── test_connection_tools.py
│ │ │ ├── test_db_management_tools.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_query_tools.py
│ │ │ └── test_write_tools.py
│ │ └── uv.lock
│ ├── dynamodb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── dynamodb_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── database_analysis_queries.py
│ │ │ ├── database_analyzers.py
│ │ │ ├── prompts
│ │ │ │ └── dynamodb_architect.md
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── evals
│ │ │ │ ├── dynamic_evaluators.py
│ │ │ │ ├── evaluation_registry.py
│ │ │ │ ├── logging_config.py
│ │ │ │ ├── multiturn_evaluator.py
│ │ │ │ ├── README.md
│ │ │ │ ├── scenarios.py
│ │ │ │ └── test_dspy_evals.py
│ │ │ ├── test_dynamodb_server.py
│ │ │ └── test_source_db_integration.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── ecs-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── ecs_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── __init__.py
│ │ │ │ ├── containerize.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── ecs_troubleshooting.py
│ │ │ │ ├── infrastructure.py
│ │ │ │ ├── resource_management.py
│ │ │ │ ├── status.py
│ │ │ │ └── troubleshooting_tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── detect_image_pull_failures.py
│ │ │ │ ├── fetch_cloudformation_status.py
│ │ │ │ ├── fetch_network_configuration.py
│ │ │ │ ├── fetch_service_events.py
│ │ │ │ ├── fetch_task_failures.py
│ │ │ │ ├── fetch_task_logs.py
│ │ │ │ ├── get_ecs_troubleshooting_guidance.py
│ │ │ │ └── utils.py
│ │ │ ├── main.py
│ │ │ ├── modules
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_knowledge_proxy.py
│ │ │ │ ├── containerize.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── deployment_status.py
│ │ │ │ ├── infrastructure.py
│ │ │ │ ├── resource_management.py
│ │ │ │ └── troubleshooting.py
│ │ │ ├── templates
│ │ │ │ ├── ecr_infrastructure.json
│ │ │ │ └── ecs_infrastructure.json
│ │ │ └── utils
│ │ │ ├── arn_parser.py
│ │ │ ├── aws.py
│ │ │ ├── config.py
│ │ │ ├── docker.py
│ │ │ ├── security.py
│ │ │ ├── templates.py
│ │ │ └── time_utils.py
│ │ ├── DEVELOPMENT.md
│ │ ├── pyproject.toml
│ │ ├── pyrightconfig.json
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── integ
│ │ │ │ └── mcp-inspector
│ │ │ │ ├── .gitignore
│ │ │ │ ├── README.md
│ │ │ │ ├── run-tests.sh
│ │ │ │ └── scenarios
│ │ │ │ ├── 01_comprehensive_troubleshooting
│ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ ├── 03_cleanup.sh
│ │ │ │ │ ├── description.txt
│ │ │ │ │ └── utils
│ │ │ │ │ ├── mcp_helpers.sh
│ │ │ │ │ └── validation_helpers.sh
│ │ │ │ └── 02_test_knowledge_proxy_tools
│ │ │ │ ├── 01_create.sh
│ │ │ │ ├── 02_validate.sh
│ │ │ │ ├── 03_cleanup.sh
│ │ │ │ ├── description.txt
│ │ │ │ └── utils
│ │ │ │ ├── knowledge_validation_helpers.sh
│ │ │ │ └── mcp_knowledge_helpers.sh
│ │ │ ├── llm_testing
│ │ │ │ ├── invalid_cfn_template.yaml
│ │ │ │ ├── README.md
│ │ │ │ ├── run_tests.sh
│ │ │ │ ├── scenarios
│ │ │ │ │ ├── 01_cloudformation_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 02_service_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 03_task_exit_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 04_network_configuration_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 05_resource_constraint_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ └── 06_load_balancer_failure
│ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ └── description.txt
│ │ │ │ ├── SCRIPT_IMPROVEMENTS.md
│ │ │ │ └── utils
│ │ │ │ ├── aws_helpers.sh
│ │ │ │ └── evaluation_template.md
│ │ │ └── unit
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_delete_api.py
│ │ │ │ ├── test_ecs_troubleshooting.py
│ │ │ │ ├── test_resource_management_api.py
│ │ │ │ └── troubleshooting_tools
│ │ │ │ └── test_fetch_network_configuration.py
│ │ │ ├── conftest.py
│ │ │ ├── modules
│ │ │ │ ├── test_aws_knowledge_proxy.py
│ │ │ │ └── test_resource_management_module.py
│ │ │ ├── test_aws_role_utils.py
│ │ │ ├── test_aws_utils.py
│ │ │ ├── test_containerize.py
│ │ │ ├── test_delete.py
│ │ │ ├── test_docker_utils.py
│ │ │ ├── test_docker_with_role.py
│ │ │ ├── test_image_pull_failure_extended.py
│ │ │ ├── test_image_pull_failure.py
│ │ │ ├── test_infrastructure_role.py
│ │ │ ├── test_infrastructure.py
│ │ │ ├── test_integration.py
│ │ │ ├── test_main.py
│ │ │ ├── test_resource_management_api_operation.py
│ │ │ ├── test_resource_management_tool.py
│ │ │ ├── test_resource_management.py
│ │ │ ├── test_security_integration.py
│ │ │ ├── test_status_pytest.py
│ │ │ ├── test_status.py
│ │ │ ├── troubleshooting_tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_detect_image_pull_failures.py
│ │ │ │ ├── test_fetch_cloudformation_status.py
│ │ │ │ ├── test_fetch_service_events.py
│ │ │ │ ├── test_fetch_task_failures.py
│ │ │ │ ├── test_fetch_task_logs.py
│ │ │ │ ├── test_get_ecs_troubleshooting_guidance.py
│ │ │ │ ├── test_is_ecr_image_security.py
│ │ │ │ └── test_utils.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── async_test_utils.py
│ │ │ ├── test_arn_parser.py
│ │ │ ├── test_config.py
│ │ │ ├── test_docker.py
│ │ │ ├── test_response_sanitization.py
│ │ │ ├── test_security_extended.py
│ │ │ ├── test_security.py
│ │ │ ├── test_templates.py
│ │ │ └── test_time_utils.py
│ │ └── uv.lock
│ ├── eks-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── eks_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ ├── cloudwatch_handler.py
│ │ │ ├── cloudwatch_metrics_guidance_handler.py
│ │ │ ├── consts.py
│ │ │ ├── data
│ │ │ │ └── eks_cloudwatch_metrics_guidance.json
│ │ │ ├── eks_kb_handler.py
│ │ │ ├── eks_stack_handler.py
│ │ │ ├── iam_handler.py
│ │ │ ├── insights_handler.py
│ │ │ ├── k8s_apis.py
│ │ │ ├── k8s_client_cache.py
│ │ │ ├── k8s_handler.py
│ │ │ ├── logging_helper.py
│ │ │ ├── models.py
│ │ │ ├── scripts
│ │ │ │ └── update_eks_cloudwatch_metrics_guidance.py
│ │ │ ├── server.py
│ │ │ ├── templates
│ │ │ │ ├── eks-templates
│ │ │ │ │ └── eks-with-vpc.yaml
│ │ │ │ └── k8s-templates
│ │ │ │ ├── deployment.yaml
│ │ │ │ └── service.yaml
│ │ │ └── vpc_config_handler.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_cloudwatch_handler.py
│ │ │ ├── test_cloudwatch_metrics_guidance_handler.py
│ │ │ ├── test_eks_kb_handler.py
│ │ │ ├── test_eks_stack_handler.py
│ │ │ ├── test_iam_handler.py
│ │ │ ├── test_init.py
│ │ │ ├── test_insights_handler.py
│ │ │ ├── test_k8s_apis.py
│ │ │ ├── test_k8s_client_cache.py
│ │ │ ├── test_k8s_handler.py
│ │ │ ├── test_logging_helper.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_vpc_config_handler.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── elasticache-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── elasticache_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── __init__.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── decorators.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ └── tools
│ │ │ ├── __init__.py
│ │ │ ├── cc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── connect.py
│ │ │ │ ├── create.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── describe.py
│ │ │ │ ├── modify.py
│ │ │ │ ├── parsers.py
│ │ │ │ └── processors.py
│ │ │ ├── ce
│ │ │ │ ├── __init__.py
│ │ │ │ └── get_cost_and_usage.py
│ │ │ ├── cw
│ │ │ │ ├── __init__.py
│ │ │ │ └── get_metric_statistics.py
│ │ │ ├── cwlogs
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_log_group.py
│ │ │ │ ├── describe_log_groups.py
│ │ │ │ ├── describe_log_streams.py
│ │ │ │ ├── filter_log_events.py
│ │ │ │ └── get_log_events.py
│ │ │ ├── firehose
│ │ │ │ ├── __init__.py
│ │ │ │ └── list_delivery_streams.py
│ │ │ ├── misc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── batch_apply_update_action.py
│ │ │ │ ├── batch_stop_update_action.py
│ │ │ │ ├── describe_cache_engine_versions.py
│ │ │ │ ├── describe_engine_default_parameters.py
│ │ │ │ ├── describe_events.py
│ │ │ │ └── describe_service_updates.py
│ │ │ ├── rg
│ │ │ │ ├── __init__.py
│ │ │ │ ├── complete_migration.py
│ │ │ │ ├── connect.py
│ │ │ │ ├── create.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── describe.py
│ │ │ │ ├── modify.py
│ │ │ │ ├── parsers.py
│ │ │ │ ├── processors.py
│ │ │ │ ├── start_migration.py
│ │ │ │ └── test_migration.py
│ │ │ └── serverless
│ │ │ ├── __init__.py
│ │ │ ├── connect.py
│ │ │ ├── create.py
│ │ │ ├── delete.py
│ │ │ ├── describe.py
│ │ │ ├── models.py
│ │ │ └── modify.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_connection.py
│ │ │ ├── test_decorators.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── tools
│ │ │ ├── cc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_connect_additional.py
│ │ │ │ ├── test_connect_coverage_additional.py
│ │ │ │ ├── test_connect_coverage.py
│ │ │ │ ├── test_connect.py
│ │ │ │ ├── test_create_additional.py
│ │ │ │ ├── test_create.py
│ │ │ │ ├── test_delete.py
│ │ │ │ ├── test_describe.py
│ │ │ │ ├── test_modify.py
│ │ │ │ ├── test_parsers.py
│ │ │ │ └── test_processors.py
│ │ │ ├── ce
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_get_cost_and_usage.py
│ │ │ ├── cw
│ │ │ │ └── test_get_metric_statistics.py
│ │ │ ├── cwlogs
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_create_log_group.py
│ │ │ │ ├── test_describe_log_groups.py
│ │ │ │ ├── test_describe_log_streams.py
│ │ │ │ ├── test_filter_log_events.py
│ │ │ │ └── test_get_log_events.py
│ │ │ ├── firehose
│ │ │ │ └── test_list_delivery_streams.py
│ │ │ ├── misc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_batch_apply_update_action.py
│ │ │ │ ├── test_batch_stop_update_action.py
│ │ │ │ ├── test_describe_cache_engine_versions.py
│ │ │ │ ├── test_describe_engine_default_parameters.py
│ │ │ │ ├── test_describe_events.py
│ │ │ │ └── test_describe_service_updates.py
│ │ │ ├── rg
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_complete_migration.py
│ │ │ │ ├── test_connect_additional.py
│ │ │ │ ├── test_connect_coverage_additional.py
│ │ │ │ ├── test_connect_optional_fields.py
│ │ │ │ ├── test_connect_partial_coverage.py
│ │ │ │ ├── test_connect.py
│ │ │ │ ├── test_create.py
│ │ │ │ ├── test_delete.py
│ │ │ │ ├── test_describe.py
│ │ │ │ ├── test_modify.py
│ │ │ │ ├── test_parsers.py
│ │ │ │ ├── test_processors.py
│ │ │ │ ├── test_start_migration.py
│ │ │ │ └── test_test_migration.py
│ │ │ └── serverless
│ │ │ ├── test_connect_additional.py
│ │ │ ├── test_connect_coverage_additional.py
│ │ │ ├── test_connect_optional_fields.py
│ │ │ ├── test_connect.py
│ │ │ ├── test_create.py
│ │ │ ├── test_delete.py
│ │ │ ├── test_describe.py
│ │ │ └── test_modify.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── finch-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── finch_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── build.py
│ │ │ ├── common.py
│ │ │ ├── ecr.py
│ │ │ ├── push.py
│ │ │ └── vm.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_cli_flags.py
│ │ │ ├── test_logging_configuration.py
│ │ │ ├── test_server.py
│ │ │ ├── test_utils_build.py
│ │ │ ├── test_utils_common.py
│ │ │ ├── test_utils_ecr.py
│ │ │ ├── test_utils_push.py
│ │ │ └── test_utils_vm.py
│ │ └── uv.lock
│ ├── frontend-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── frontend_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ ├── static
│ │ │ │ └── react
│ │ │ │ ├── essential-knowledge.md
│ │ │ │ └── troubleshooting.md
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ └── file_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_file_utils.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ └── uv.lock
│ ├── git-repo-research-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── git_repo_research_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── defaults.py
│ │ │ ├── embeddings.py
│ │ │ ├── github_search.py
│ │ │ ├── indexer.py
│ │ │ ├── models.py
│ │ │ ├── repository.py
│ │ │ ├── search.py
│ │ │ ├── server.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_errors_repository.py
│ │ │ ├── test_github_search_edge_cases.py
│ │ │ ├── test_graphql_github_search.py
│ │ │ ├── test_local_repository.py
│ │ │ ├── test_repository_utils.py
│ │ │ ├── test_rest_github_search.py
│ │ │ ├── test_search.py
│ │ │ ├── test_server.py
│ │ │ └── test_url_repository.py
│ │ └── uv.lock
│ ├── healthlake-mcp-server
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── healthlake_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── fhir_operations.py
│ │ │ ├── main.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── mcp_config.json
│ │ │ └── README.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_fhir_client_comprehensive.py
│ │ │ ├── test_fhir_error_scenarios.py
│ │ │ ├── test_fhir_operations.py
│ │ │ ├── test_integration_mock_based.py
│ │ │ ├── test_main_edge_cases.py
│ │ │ ├── test_main.py
│ │ │ ├── test_mcp_integration_coverage.py
│ │ │ ├── test_models_edge_cases.py
│ │ │ ├── test_models.py
│ │ │ ├── test_readonly_mode.py
│ │ │ ├── test_server_core.py
│ │ │ ├── test_server_error_handling.py
│ │ │ ├── test_server_mcp_handlers.py
│ │ │ ├── test_server_toolhandler.py
│ │ │ └── test_server_validation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── iam-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── iam_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── DESIGN_COMPLIANCE.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── get_policy_document_example.py
│ │ │ └── inline_policy_demo.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── test_context.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_inline_policies.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── lambda-tool-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── lambda_tool_mcp_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── README.md
│ │ │ └── sample_functions
│ │ │ ├── customer-create
│ │ │ │ └── app.py
│ │ │ ├── customer-id-from-email
│ │ │ │ └── app.py
│ │ │ ├── customer-info-from-id
│ │ │ │ └── app.py
│ │ │ └── template.yml
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_format_lambda_response.py
│ │ │ ├── test_integration_coverage.py
│ │ │ ├── test_integration.py
│ │ │ ├── test_register_lambda_functions.py
│ │ │ ├── test_schema_integration.py
│ │ │ ├── test_server_coverage_additional.py
│ │ │ ├── test_server_coverage.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── mcp-lambda-handler
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ └── mcp_lambda_handler
│ │ │ ├── __init__.py
│ │ │ ├── mcp_lambda_handler.py
│ │ │ ├── session.py
│ │ │ └── types.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ └── test_lambda_handler.py
│ │ └── uv.lock
│ ├── memcached-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── memcached_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── config.py
│ │ │ │ ├── connection.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ └── tools
│ │ │ └── cache.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── ELASTICACHECONNECT.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_cache_readonly.py
│ │ │ ├── test_cache.py
│ │ │ ├── test_connection.py
│ │ │ ├── test_init.py
│ │ │ └── test_main.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── mysql-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── mysql_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── nova-canvas-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── nova_canvas_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── novacanvas.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_models.py
│ │ │ ├── test_novacanvas.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── openapi-mcp-server
│ │ ├── .coveragerc
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── AUTHENTICATION.md
│ │ ├── AWS_BEST_PRACTICES.md
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── openapi_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── __init__.py
│ │ │ │ └── config.py
│ │ │ ├── auth
│ │ │ │ ├── __init__.py
│ │ │ │ ├── api_key_auth.py
│ │ │ │ ├── auth_cache.py
│ │ │ │ ├── auth_errors.py
│ │ │ │ ├── auth_factory.py
│ │ │ │ ├── auth_protocol.py
│ │ │ │ ├── auth_provider.py
│ │ │ │ ├── base_auth.py
│ │ │ │ ├── basic_auth.py
│ │ │ │ ├── bearer_auth.py
│ │ │ │ ├── cognito_auth.py
│ │ │ │ └── register.py
│ │ │ ├── patch
│ │ │ │ └── __init__.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── generators
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── operation_prompts.py
│ │ │ │ │ └── workflow_prompts.py
│ │ │ │ ├── models.py
│ │ │ │ └── prompt_manager.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── cache_provider.py
│ │ │ ├── config.py
│ │ │ ├── error_handler.py
│ │ │ ├── http_client.py
│ │ │ ├── metrics_provider.py
│ │ │ ├── openapi_validator.py
│ │ │ └── openapi.py
│ │ ├── CHANGELOG.md
│ │ ├── DEPLOYMENT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── OBSERVABILITY.md
│ │ ├── pyproject.toml
│ │ ├── pyrightconfig.json
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── api
│ │ │ │ └── test_config.py
│ │ │ ├── auth
│ │ │ │ ├── test_api_key_auth.py
│ │ │ │ ├── test_auth_cache.py
│ │ │ │ ├── test_auth_errors.py
│ │ │ │ ├── test_auth_factory_caching.py
│ │ │ │ ├── test_auth_factory_coverage.py
│ │ │ │ ├── test_auth_factory.py
│ │ │ │ ├── test_auth_protocol_additional.py
│ │ │ │ ├── test_auth_protocol_boost.py
│ │ │ │ ├── test_auth_protocol_coverage.py
│ │ │ │ ├── test_auth_protocol_extended.py
│ │ │ │ ├── test_auth_protocol_improved.py
│ │ │ │ ├── test_auth_protocol.py
│ │ │ │ ├── test_auth_provider_additional.py
│ │ │ │ ├── test_base_auth_coverage.py
│ │ │ │ ├── test_base_auth.py
│ │ │ │ ├── test_basic_auth.py
│ │ │ │ ├── test_bearer_auth.py
│ │ │ │ ├── test_cognito_auth_additional_coverage.py
│ │ │ │ ├── test_cognito_auth_boost_coverage.py
│ │ │ │ ├── test_cognito_auth_client_credentials.py
│ │ │ │ ├── test_cognito_auth_coverage_boost.py
│ │ │ │ ├── test_cognito_auth_exceptions.py
│ │ │ │ ├── test_cognito_auth.py
│ │ │ │ ├── test_register_coverage.py
│ │ │ │ └── test_register.py
│ │ │ ├── prompts
│ │ │ │ ├── standalone
│ │ │ │ │ ├── test_operation_prompt.py
│ │ │ │ │ ├── test_prompt_arguments.py
│ │ │ │ │ └── test_secure_operation_prompt.py
│ │ │ │ ├── test_mcp_prompt_manager_integration.py
│ │ │ │ ├── test_mcp_prompt_manager.py
│ │ │ │ ├── test_models_dict_method.py
│ │ │ │ ├── test_operation_prompts_extended.py
│ │ │ │ ├── test_prompt_manager_additional.py
│ │ │ │ ├── test_prompt_manager_comprehensive.py
│ │ │ │ ├── test_prompt_manager_coverage.py
│ │ │ │ └── test_prompt_registration.py
│ │ │ ├── README.md
│ │ │ ├── test_api_name.py
│ │ │ ├── test_cache_coverage_89.py
│ │ │ ├── test_client.py
│ │ │ ├── test_coverage_boost.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main_extended.py
│ │ │ ├── test_main.py
│ │ │ ├── test_openapi_coverage_89.py
│ │ │ ├── test_server_auth_errors.py
│ │ │ ├── test_server_coverage_boost_2.py
│ │ │ ├── test_server_coverage_boost.py
│ │ │ ├── test_server_exception_handling.py
│ │ │ ├── test_server_extended.py
│ │ │ ├── test_server_httpx_version.py
│ │ │ ├── test_server_part1.py
│ │ │ ├── test_server_route_logging.py
│ │ │ ├── test_server_signal_handlers.py
│ │ │ ├── test_server.py
│ │ │ └── utils
│ │ │ ├── test_cache_provider.py
│ │ │ ├── test_error_handler_boost.py
│ │ │ ├── test_error_handler_extended.py
│ │ │ ├── test_error_handler_fix.py
│ │ │ ├── test_error_handler.py
│ │ │ ├── test_http_client_comprehensive.py
│ │ │ ├── test_http_client_extended.py
│ │ │ ├── test_http_client_extended2.py
│ │ │ ├── test_http_client_import_error.py
│ │ │ ├── test_http_client.py
│ │ │ ├── test_metrics_provider_decorators.py
│ │ │ ├── test_metrics_provider_extended2.py
│ │ │ ├── test_metrics_provider_prometheus.py
│ │ │ ├── test_metrics_provider.py
│ │ │ ├── test_openapi_validator.py
│ │ │ └── test_openapi.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── postgres-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── postgres_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── connection
│ │ │ │ ├── __init__.py
│ │ │ │ ├── abstract_db_connection.py
│ │ │ │ ├── db_connection_singleton.py
│ │ │ │ ├── psycopg_pool_connection.py
│ │ │ │ └── rds_api_connection.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_psycopg_connector.py
│ │ │ ├── test_server.py
│ │ │ └── test_singleton.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── prometheus-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── prometheus_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_aws_credentials.py
│ │ │ ├── test_config_manager.py
│ │ │ ├── test_consts.py
│ │ │ ├── test_coverage_gaps.py
│ │ │ ├── test_coverage_improvement.py
│ │ │ ├── test_final_coverage.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_prometheus_client.py
│ │ │ ├── test_prometheus_connection.py
│ │ │ ├── test_security_validator.py
│ │ │ ├── test_server_coverage.py
│ │ │ ├── test_tools.py
│ │ │ └── test_workspace_config.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── redshift-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── redshift_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── redshift.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_redshift.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── s3-tables-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── s3_tables_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── database.py
│ │ │ ├── engines
│ │ │ │ ├── __init__.py
│ │ │ │ └── pyiceberg.py
│ │ │ ├── file_processor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── csv.py
│ │ │ │ ├── parquet.py
│ │ │ │ └── utils.py
│ │ │ ├── models.py
│ │ │ ├── namespaces.py
│ │ │ ├── resources.py
│ │ │ ├── s3_operations.py
│ │ │ ├── server.py
│ │ │ ├── table_buckets.py
│ │ │ ├── tables.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTEXT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_csv.py
│ │ │ ├── test_database.py
│ │ │ ├── test_file_processor_utils.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_namespaces.py
│ │ │ ├── test_parquet.py
│ │ │ ├── test_pyiceberg.py
│ │ │ ├── test_resources.py
│ │ │ ├── test_s3_operations.py
│ │ │ ├── test_server.py
│ │ │ ├── test_table_buckets.py
│ │ │ ├── test_tables.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── stepfunctions-tool-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── stepfunctions_tool_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_create_state_machine_tool.py
│ │ │ ├── test_filter_state_machines_by_tag.py
│ │ │ ├── test_format_state_machine_response.py
│ │ │ ├── test_get_schema_arn_from_state_machine_arn.py
│ │ │ ├── test_get_schema_from_registry.py
│ │ │ ├── test_invoke_express_state_machine_impl.py
│ │ │ ├── test_invoke_standard_state_machine_impl.py
│ │ │ ├── test_main.py
│ │ │ ├── test_register_state_machines.py
│ │ │ ├── test_sanitize_tool_name.py
│ │ │ ├── test_server.py
│ │ │ └── test_validate_state_machine_name.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── syntheticdata-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── syntheticdata_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── pandas_interpreter.py
│ │ │ ├── server.py
│ │ │ └── storage
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── loader.py
│ │ │ └── s3.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_constants.py
│ │ │ ├── test_pandas_interpreter.py
│ │ │ ├── test_server.py
│ │ │ └── test_storage
│ │ │ ├── __init__.py
│ │ │ ├── test_loader.py
│ │ │ └── test_s3.py
│ │ └── uv.lock
│ ├── terraform-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── terraform_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── impl
│ │ │ │ ├── resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── terraform_aws_provider_resources_listing.py
│ │ │ │ │ └── terraform_awscc_provider_resources_listing.py
│ │ │ │ └── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── execute_terraform_command.py
│ │ │ │ ├── execute_terragrunt_command.py
│ │ │ │ ├── run_checkov_scan.py
│ │ │ │ ├── search_aws_provider_docs.py
│ │ │ │ ├── search_awscc_provider_docs.py
│ │ │ │ ├── search_specific_aws_ia_modules.py
│ │ │ │ ├── search_user_provided_module.py
│ │ │ │ └── utils.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ └── models.py
│ │ │ ├── scripts
│ │ │ │ ├── generate_aws_provider_resources.py
│ │ │ │ ├── generate_awscc_provider_resources.py
│ │ │ │ └── scrape_aws_terraform_best_practices.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ ├── AWS_PROVIDER_RESOURCES.md
│ │ │ ├── AWS_TERRAFORM_BEST_PRACTICES.md
│ │ │ ├── AWSCC_PROVIDER_RESOURCES.md
│ │ │ ├── MCP_INSTRUCTIONS.md
│ │ │ └── TERRAFORM_WORKFLOW_GUIDE.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_command_impl.py
│ │ │ ├── test_execute_terraform_command.py
│ │ │ ├── test_execute_terragrunt_command.py
│ │ │ ├── test_models.py
│ │ │ ├── test_parameter_annotations.py
│ │ │ ├── test_resources.py
│ │ │ ├── test_run_checkov_scan.py
│ │ │ ├── test_search_user_provided_module.py
│ │ │ ├── test_server.py
│ │ │ ├── test_tool_implementations.py
│ │ │ ├── test_utils_additional.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── timestream-for-influxdb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── timestream_for_influxdb_mcp_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── valkey-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── valkey_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── __init__.py
│ │ │ │ ├── config.py
│ │ │ │ ├── connection.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bitmap.py
│ │ │ │ ├── hash.py
│ │ │ │ ├── hyperloglog.py
│ │ │ │ ├── json.py
│ │ │ │ ├── list.py
│ │ │ │ ├── misc.py
│ │ │ │ ├── server_management.py
│ │ │ │ ├── set.py
│ │ │ │ ├── sorted_set.py
│ │ │ │ ├── stream.py
│ │ │ │ └── string.py
│ │ │ └── version.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── ELASTICACHECONNECT.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_bitmap.py
│ │ │ ├── test_config.py
│ │ │ ├── test_connection.py
│ │ │ ├── test_hash.py
│ │ │ ├── test_hyperloglog.py
│ │ │ ├── test_init.py
│ │ │ ├── test_json_additional.py
│ │ │ ├── test_json_readonly.py
│ │ │ ├── test_json.py
│ │ │ ├── test_list_additional.py
│ │ │ ├── test_list_readonly.py
│ │ │ ├── test_list.py
│ │ │ ├── test_main.py
│ │ │ ├── test_misc.py
│ │ │ ├── test_server_management.py
│ │ │ ├── test_set_readonly.py
│ │ │ ├── test_set.py
│ │ │ ├── test_sorted_set_additional.py
│ │ │ ├── test_sorted_set_readonly.py
│ │ │ ├── test_sorted_set.py
│ │ │ ├── test_stream_additional.py
│ │ │ ├── test_stream_readonly.py
│ │ │ ├── test_stream.py
│ │ │ └── test_string.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ └── well-architected-security-mcp-server
│ ├── .python-version
│ ├── awslabs
│ │ └── well_architected_security_mcp_server
│ │ ├── __init__.py
│ │ ├── consts.py
│ │ ├── server.py
│ │ └── util
│ │ ├── __init__.py
│ │ ├── network_security.py
│ │ ├── prompt_utils.py
│ │ ├── resource_utils.py
│ │ ├── security_services.py
│ │ └── storage_security.py
│ ├── PROMPT_TEMPLATE.md
│ ├── pyproject.toml
│ ├── README.md
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── README.md
│ │ ├── test_access_analyzer_fix.py
│ │ ├── test_network_security_additional.py
│ │ ├── test_network_security.py
│ │ ├── test_prompt_utils_coverage.py
│ │ ├── test_prompt_utils.py
│ │ ├── test_resource_utils_fix.py
│ │ ├── test_resource_utils.py
│ │ ├── test_security_services_additional.py
│ │ ├── test_security_services_coverage.py
│ │ ├── test_security_services.py
│ │ ├── test_server_additional.py
│ │ ├── test_server_coverage.py
│ │ ├── test_server_prompts.py
│ │ ├── test_server_security_findings.py
│ │ ├── test_server.py
│ │ ├── test_storage_security_additional.py
│ │ ├── test_storage_security_comprehensive.py
│ │ ├── test_storage_security_edge_cases.py
│ │ ├── test_storage_security_recommendations.py
│ │ ├── test_storage_security.py
│ │ └── test_user_agent_config.py
│ └── uv.lock
└── VIBE_CODING_TIPS_TRICKS.md
```
# Files
--------------------------------------------------------------------------------
/src/aws-dataprocessing-mcp-server/tests/handlers/glue/test_data_catalog_handler.py:
--------------------------------------------------------------------------------
```python
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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 | """Tests for the Glue Data Catalog Handler."""
16 |
17 | import pytest
18 | from awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler import (
19 | GlueDataCatalogHandler,
20 | )
21 | from unittest.mock import ANY, AsyncMock, MagicMock, patch
22 |
23 |
24 | class TestGlueDataCatalogHandler:
25 | """Tests for the GlueDataCatalogHandler class."""
26 |
27 | @pytest.fixture
28 | def mock_mcp(self):
29 | """Create a mock MCP server."""
30 | mock = MagicMock()
31 | return mock
32 |
33 | @pytest.fixture
34 | def mock_ctx(self):
35 | """Create a mock Context."""
36 | mock = MagicMock()
37 | return mock
38 |
39 | @pytest.fixture
40 | def mock_database_manager(self):
41 | """Create a mock DataCatalogDatabaseManager."""
42 | mock = AsyncMock()
43 | return mock
44 |
45 | @pytest.fixture
46 | def mock_table_manager(self):
47 | """Create a mock DataCatalogTableManager."""
48 | mock = AsyncMock()
49 | return mock
50 |
51 | @pytest.fixture
52 | def mock_catalog_manager(self):
53 | """Create a mock DataCatalogManager."""
54 | mock = AsyncMock()
55 | return mock
56 |
57 | @pytest.fixture
58 | def handler(self, mock_mcp, mock_database_manager, mock_table_manager, mock_catalog_manager):
59 | """Create a GlueDataCatalogHandler instance with mocked dependencies."""
60 | with (
61 | patch(
62 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogDatabaseManager',
63 | return_value=mock_database_manager,
64 | ),
65 | patch(
66 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogTableManager',
67 | return_value=mock_table_manager,
68 | ),
69 | patch(
70 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogManager',
71 | return_value=mock_catalog_manager,
72 | ),
73 | ):
74 | handler = GlueDataCatalogHandler(mock_mcp)
75 | handler.data_catalog_database_manager = mock_database_manager
76 | handler.data_catalog_table_manager = mock_table_manager
77 | handler.data_catalog_manager = mock_catalog_manager
78 | return handler
79 |
80 | @pytest.fixture
81 | def handler_with_write_access(
82 | self, mock_mcp, mock_database_manager, mock_table_manager, mock_catalog_manager
83 | ):
84 | """Create a GlueDataCatalogHandler instance with write access enabled."""
85 | with (
86 | patch(
87 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogDatabaseManager',
88 | return_value=mock_database_manager,
89 | ),
90 | patch(
91 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogTableManager',
92 | return_value=mock_table_manager,
93 | ),
94 | patch(
95 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogManager',
96 | return_value=mock_catalog_manager,
97 | ),
98 | ):
99 | handler = GlueDataCatalogHandler(mock_mcp, allow_write=True)
100 | handler.data_catalog_database_manager = mock_database_manager
101 | handler.data_catalog_table_manager = mock_table_manager
102 | handler.data_catalog_manager = mock_catalog_manager
103 | return handler
104 |
105 | def test_initialization(self, mock_mcp):
106 | """Test that the handler is initialized correctly."""
107 | # Mock the AWS helper's create_boto3_client method to avoid boto3 client creation
108 | with patch(
109 | 'awslabs.aws_dataprocessing_mcp_server.utils.aws_helper.AwsHelper.create_boto3_client',
110 | return_value=MagicMock(),
111 | ):
112 | handler = GlueDataCatalogHandler(mock_mcp)
113 |
114 | # Verify that the handler has the correct attributes
115 | assert handler.mcp == mock_mcp
116 | assert handler.allow_write is False
117 | assert handler.allow_sensitive_data_access is False
118 |
119 | # Verify that the tools were registered
120 | assert mock_mcp.tool.call_count == 5
121 |
122 | # Get all call args
123 | call_args_list = mock_mcp.tool.call_args_list
124 |
125 | # Get all tool names that were registered
126 | tool_names = [call_args[1]['name'] for call_args in call_args_list]
127 |
128 | # Verify that expected tools are registered
129 | assert 'manage_aws_glue_databases' in tool_names
130 | assert 'manage_aws_glue_tables' in tool_names
131 | assert 'manage_aws_glue_connections' in tool_names
132 | assert 'manage_aws_glue_partitions' in tool_names
133 | assert 'manage_aws_glue_catalog' in tool_names
134 |
135 | def test_initialization_with_write_access(self, mock_mcp):
136 | """Test that the handler is initialized correctly with write access."""
137 | # Mock the AWS helper's create_boto3_client method to avoid boto3 client creation
138 | with patch(
139 | 'awslabs.aws_dataprocessing_mcp_server.utils.aws_helper.AwsHelper.create_boto3_client',
140 | return_value=MagicMock(),
141 | ):
142 | handler = GlueDataCatalogHandler(mock_mcp, allow_write=True)
143 |
144 | # Verify that the handler has the correct attributes
145 | assert handler.mcp == mock_mcp
146 | assert handler.allow_write is True
147 | assert handler.allow_sensitive_data_access is False
148 |
149 | def test_initialization_with_sensitive_data_access(self, mock_mcp):
150 | """Test that the handler is initialized correctly with sensitive data access."""
151 | # Mock the AWS helper's create_boto3_client method to avoid boto3 client creation
152 | with patch(
153 | 'awslabs.aws_dataprocessing_mcp_server.utils.aws_helper.AwsHelper.create_boto3_client',
154 | return_value=MagicMock(),
155 | ):
156 | handler = GlueDataCatalogHandler(mock_mcp, allow_sensitive_data_access=True)
157 |
158 | # Verify that the handler has the correct attributes
159 | assert handler.mcp == mock_mcp
160 | assert handler.allow_write is False
161 | assert handler.allow_sensitive_data_access is True
162 |
163 | @pytest.mark.asyncio
164 | async def test_manage_aws_glue_data_catalog_databases_create_no_write_access(
165 | self, handler, mock_ctx
166 | ):
167 | """Test that create database operation is not allowed without write access."""
168 | # Mock the response class
169 | mock_response = MagicMock()
170 | mock_response.isError = True
171 | mock_response.content = [MagicMock()]
172 | mock_response.content[
173 | 0
174 | ].text = 'Operation create-database is not allowed without write access'
175 | mock_response.database_name = ''
176 | mock_response.operation = 'create'
177 |
178 | # Patch the CreateDatabaseResponse class
179 | with patch(
180 | 'awslabs.aws_dataprocessing_mcp_server.models.data_catalog_models.CreateDatabaseResponse',
181 | return_value=mock_response,
182 | ):
183 | # Call the method with a write operation
184 | result = await handler.manage_aws_glue_data_catalog_databases(
185 | mock_ctx, operation='create-database', database_name='test-db'
186 | )
187 |
188 | # Verify the result
189 | assert result.isError is True
190 | assert 'not allowed without write access' in result.content[0].text
191 | assert result.database_name == ''
192 | assert result.operation == 'create-database'
193 |
194 | @pytest.mark.asyncio
195 | async def test_manage_aws_glue_data_catalog_databases_delete_no_write_access(
196 | self, handler, mock_ctx
197 | ):
198 | """Test that delete database operation is not allowed without write access."""
199 | # Mock the response class
200 | mock_response = MagicMock()
201 | mock_response.isError = True
202 | mock_response.content = [MagicMock()]
203 | mock_response.content[
204 | 0
205 | ].text = 'Operation delete-database is not allowed without write access'
206 | mock_response.database_name = ''
207 | mock_response.operation = 'delete'
208 |
209 | # Patch the DeleteDatabaseResponse class
210 | with patch(
211 | 'awslabs.aws_dataprocessing_mcp_server.models.data_catalog_models.DeleteDatabaseResponse',
212 | return_value=mock_response,
213 | ):
214 | # Call the method with a write operation
215 | result = await handler.manage_aws_glue_data_catalog_databases(
216 | mock_ctx, operation='delete-database', database_name='test-db'
217 | )
218 |
219 | # Verify the result
220 | assert result.isError is True
221 | assert 'not allowed without write access' in result.content[0].text
222 | assert result.database_name == ''
223 | assert result.operation == 'delete-database'
224 |
225 | @pytest.mark.asyncio
226 | async def test_manage_aws_glue_data_catalog_databases_update_no_write_access(
227 | self, handler, mock_ctx
228 | ):
229 | """Test that update database operation is not allowed without write access."""
230 | # Mock the response class
231 | mock_response = MagicMock()
232 | mock_response.isError = True
233 | mock_response.content = [MagicMock()]
234 | mock_response.content[
235 | 0
236 | ].text = 'Operation update-database is not allowed without write access'
237 | mock_response.database_name = ''
238 | mock_response.operation = 'update'
239 |
240 | # Patch the UpdateDatabaseResponse class
241 | with patch(
242 | 'awslabs.aws_dataprocessing_mcp_server.models.data_catalog_models.UpdateDatabaseResponse',
243 | return_value=mock_response,
244 | ):
245 | # Call the method with a write operation
246 | result = await handler.manage_aws_glue_data_catalog_databases(
247 | mock_ctx, operation='update-database', database_name='test-db'
248 | )
249 |
250 | # Verify the result
251 | assert result.isError is True
252 | assert 'not allowed without write access' in result.content[0].text
253 | assert result.database_name == ''
254 | assert result.operation == 'update-database'
255 |
256 | @pytest.mark.asyncio
257 | async def test_manage_aws_glue_data_catalog_databases_get_read_access(
258 | self, handler, mock_ctx, mock_database_manager
259 | ):
260 | """Test that get database operation is allowed with read access."""
261 | from unittest.mock import ANY
262 |
263 | # Mock the response class
264 | mock_response = MagicMock()
265 | mock_response.isError = False
266 | mock_response.content = []
267 | mock_response.database_name = 'test-db'
268 | mock_response.description = 'Test database'
269 | mock_response.location_uri = 's3://test-bucket/'
270 | mock_response.parameters = {}
271 | mock_response.creation_time = '2023-01-01T00:00:00Z'
272 | mock_response.operation = 'get'
273 | mock_response.catalog_id = '123456789012'
274 |
275 | # Setup the mock to return a response
276 | mock_database_manager.get_database.return_value = mock_response
277 |
278 | # Call the method with a read operation
279 | result = await handler.manage_aws_glue_data_catalog_databases(
280 | mock_ctx, operation='get-database', database_name='test-db'
281 | )
282 |
283 | # Verify that the method was called with the correct parameters
284 | # Use ANY for catalog_id to handle the FieldInfo object
285 | mock_database_manager.get_database.assert_called_once_with(
286 | ctx=mock_ctx, database_name='test-db', catalog_id=ANY
287 | )
288 |
289 | # Verify that the result is the expected response
290 | assert result == mock_response
291 |
292 | @pytest.mark.asyncio
293 | async def test_manage_aws_glue_data_catalog_databases_get_missing_database_name(
294 | self, handler, mock_ctx, mock_database_manager
295 | ):
296 | """Test that get database operation is allowed with read access."""
297 | with pytest.raises(ValueError) as e:
298 | await handler.manage_aws_glue_data_catalog_databases(
299 | mock_ctx, operation='get-database', database_name=None
300 | )
301 | assert 'database_name is required' in str(e.value)
302 |
303 | @pytest.mark.asyncio
304 | async def test_manage_aws_glue_data_catalog_databases_list_read_access(
305 | self, handler, mock_ctx, mock_database_manager
306 | ):
307 | """Test that list databases operation is allowed with read access."""
308 | from unittest.mock import ANY
309 |
310 | # Mock the response class
311 | mock_response = MagicMock()
312 | mock_response.isError = False
313 | mock_response.content = []
314 | mock_response.databases = []
315 | mock_response.count = 0
316 | mock_response.catalog_id = '123456789012'
317 | mock_response.operation = 'list'
318 |
319 | # Setup the mock to return a response
320 | mock_database_manager.list_databases.return_value = mock_response
321 |
322 | # Call the method with a read operation
323 | result = await handler.manage_aws_glue_data_catalog_databases(
324 | mock_ctx, operation='list-databases'
325 | )
326 |
327 | # Verify that the method was called with the correct parameters
328 | # Use ANY for catalog_id to handle the FieldInfo object
329 | mock_database_manager.list_databases.assert_called_once_with(
330 | ctx=mock_ctx, catalog_id=ANY, max_results=ANY, next_token=ANY
331 | )
332 |
333 | # Verify that the result is the expected response
334 | assert result == mock_response
335 |
336 | @pytest.mark.asyncio
337 | async def test_manage_aws_glue_data_catalog_databases_create_with_write_access(
338 | self, handler_with_write_access, mock_ctx, mock_database_manager
339 | ):
340 | """Test that create database operation is allowed with write access."""
341 | # Setup the mock to return a response
342 | expected_response = MagicMock()
343 | expected_response.isError = False
344 | expected_response.content = []
345 | expected_response.database_name = 'test-db'
346 | expected_response.operation = 'create'
347 | mock_database_manager.create_database.return_value = expected_response
348 |
349 | # Call the method with a write operation
350 | result = await handler_with_write_access.manage_aws_glue_data_catalog_databases(
351 | mock_ctx,
352 | operation='create-database',
353 | database_name='test-db',
354 | description='Test database',
355 | location_uri='s3://test-bucket/',
356 | parameters={'key': 'value'},
357 | catalog_id='123456789012',
358 | )
359 |
360 | # Verify that the method was called with the correct parameters
361 | mock_database_manager.create_database.assert_called_once_with(
362 | ctx=mock_ctx,
363 | database_name='test-db',
364 | description='Test database',
365 | location_uri='s3://test-bucket/',
366 | parameters={'key': 'value'},
367 | catalog_id='123456789012',
368 | )
369 |
370 | # Verify that the result is the expected response
371 | assert result == expected_response
372 |
373 | @pytest.mark.asyncio
374 | async def test_manage_aws_glue_data_catalog_databases_delete_with_write_access(
375 | self, handler_with_write_access, mock_ctx, mock_database_manager
376 | ):
377 | """Test that delete database operation is allowed with write access."""
378 | # Setup the mock to return a response
379 | expected_response = MagicMock()
380 | expected_response.isError = False
381 | expected_response.content = []
382 | expected_response.database_name = 'test-db'
383 | expected_response.operation = 'delete'
384 | mock_database_manager.delete_database.return_value = expected_response
385 |
386 | # Call the method with a write operation
387 | result = await handler_with_write_access.manage_aws_glue_data_catalog_databases(
388 | mock_ctx,
389 | operation='delete-database',
390 | database_name='test-db',
391 | catalog_id='123456789012',
392 | )
393 |
394 | # Verify that the method was called with the correct parameters
395 | mock_database_manager.delete_database.assert_called_once_with(
396 | ctx=mock_ctx, database_name='test-db', catalog_id='123456789012'
397 | )
398 |
399 | # Verify that the result is the expected response
400 | assert result == expected_response
401 |
402 | @pytest.mark.asyncio
403 | async def test_manage_aws_glue_data_catalog_databases_delete_missing_database_name(
404 | self, handler_with_write_access, mock_ctx
405 | ):
406 | """Test that delete database operation with missing database name."""
407 | with pytest.raises(ValueError) as e:
408 | await handler_with_write_access.manage_aws_glue_data_catalog_databases(
409 | mock_ctx, operation='delete-database', database_name=None
410 | )
411 | assert 'database_name is required' in str(e.value)
412 |
413 | @pytest.mark.asyncio
414 | async def test_manage_aws_glue_data_catalog_databases_update_missing_database_name(
415 | self, handler_with_write_access, mock_ctx
416 | ):
417 | """Test that get database operation with write access."""
418 | with pytest.raises(ValueError) as e:
419 | await handler_with_write_access.manage_aws_glue_data_catalog_databases(
420 | mock_ctx, operation='update-database', database_name=None
421 | )
422 | assert 'database_name is required' in str(e.value)
423 |
424 | @pytest.mark.asyncio
425 | async def test_manage_aws_glue_data_catalog_databases_update_with_read_access(
426 | self, handler, mock_ctx
427 | ):
428 | """Test that updadte database operation with read access."""
429 | result = await handler.manage_aws_glue_data_catalog_databases(
430 | mock_ctx, operation='update-database', database_name=None
431 | )
432 | assert result.isError is True
433 | assert len(result.content) == 1
434 | assert 'is not allowed without write access' in result.content[0].text
435 |
436 | @pytest.mark.asyncio
437 | async def test_manage_aws_glue_data_catalog_databases_update_with_write_access(
438 | self, handler_with_write_access, mock_ctx, mock_database_manager
439 | ):
440 | """Test that update database operation is allowed with write access."""
441 | # Setup the mock to return a response
442 | expected_response = MagicMock()
443 | expected_response.isError = False
444 | expected_response.content = []
445 | expected_response.database_name = 'test-db'
446 | expected_response.operation = 'update'
447 | mock_database_manager.update_database.return_value = expected_response
448 |
449 | # Call the method with a write operation
450 | result = await handler_with_write_access.manage_aws_glue_data_catalog_databases(
451 | mock_ctx,
452 | operation='update-database',
453 | database_name='test-db',
454 | description='Updated database',
455 | location_uri='s3://updated-bucket/',
456 | parameters={'key': 'updated-value'},
457 | catalog_id='123456789012',
458 | )
459 |
460 | # Verify that the method was called with the correct parameters
461 | mock_database_manager.update_database.assert_called_once_with(
462 | ctx=mock_ctx,
463 | database_name='test-db',
464 | description='Updated database',
465 | location_uri='s3://updated-bucket/',
466 | parameters={'key': 'updated-value'},
467 | catalog_id='123456789012',
468 | )
469 |
470 | # Verify that the result is the expected response
471 | assert result == expected_response
472 |
473 | @pytest.mark.asyncio
474 | async def test_manage_aws_glue_data_catalog_databases_invalid_operation(
475 | self, handler, mock_ctx
476 | ):
477 | """Test that an invalid operation returns an error response."""
478 | # Set write access to true to bypass the "not allowed without write access" check
479 | handler.allow_write = True
480 |
481 | # Call the method with an invalid operation
482 | result = await handler.manage_aws_glue_data_catalog_databases(
483 | mock_ctx, operation='invalid-operation', database_name='test-db'
484 | )
485 |
486 | # Verify that the result is an error response
487 | assert result.isError is True
488 | assert 'Invalid operation' in result.content[0].text
489 | assert result.database_name == ''
490 | assert result.operation == 'get-database'
491 |
492 | @pytest.mark.asyncio
493 | async def test_manage_aws_glue_data_catalog_databases_missing_database_name(
494 | self, handler_with_write_access, mock_ctx
495 | ):
496 | """Test that missing database_name parameter raises a ValueError."""
497 | # Call the method without database_name
498 | with pytest.raises(ValueError) as excinfo:
499 | await handler_with_write_access.manage_aws_glue_data_catalog_databases(
500 | mock_ctx, operation='create-database', database_name=None
501 | )
502 |
503 | # Verify that the correct error message is raised
504 | assert 'database_name is required' in str(excinfo.value)
505 |
506 | @pytest.mark.asyncio
507 | async def test_manage_aws_glue_data_catalog_databases_exception_handling(
508 | self, handler, mock_ctx, mock_database_manager
509 | ):
510 | """Test that exceptions are handled correctly."""
511 | # Setup the mock to raise an exception
512 | mock_database_manager.get_database.side_effect = Exception('Test exception')
513 |
514 | # Patch the handler's method to handle the exception properly
515 | with patch.object(
516 | handler,
517 | 'manage_aws_glue_data_catalog_databases',
518 | side_effect=handler.manage_aws_glue_data_catalog_databases,
519 | ):
520 | # Create a mock response for the GetDatabaseResponse
521 | mock_response = MagicMock()
522 | mock_response.isError = True
523 | mock_response.content = [MagicMock()]
524 | mock_response.content[
525 | 0
526 | ].text = 'Error in manage_aws_glue_data_catalog_databases: Test exception'
527 | mock_response.database_name = 'test-db'
528 | mock_response.operation = 'get'
529 |
530 | # Patch the GetDatabaseResponse class
531 | with patch(
532 | 'awslabs.aws_dataprocessing_mcp_server.models.data_catalog_models.GetDatabaseResponse',
533 | return_value=mock_response,
534 | ):
535 | # Call the method
536 | result = await handler.manage_aws_glue_data_catalog_databases(
537 | mock_ctx, operation='get-database', database_name='test-db'
538 | )
539 |
540 | # Verify that the result is an error response
541 | assert result.isError is True
542 | assert (
543 | 'Error in manage_aws_glue_data_catalog_databases: Test exception'
544 | in result.content[0].text
545 | )
546 | assert result.database_name == 'test-db'
547 | assert result.operation == 'get-database'
548 |
549 | # Tests for manage_aws_glue_data_catalog_tables method
550 |
551 | @pytest.mark.asyncio
552 | async def test_manage_aws_glue_data_catalog_tables_create_no_write_access(
553 | self, handler, mock_ctx
554 | ):
555 | """Test that create table operation is not allowed without write access."""
556 | # Call the method with a write operation
557 | result = await handler.manage_aws_glue_data_catalog_tables(
558 | mock_ctx,
559 | operation='create-table',
560 | database_name='test-db',
561 | table_name='test-table',
562 | table_input={},
563 | )
564 |
565 | # Verify that the result is an error response
566 | assert result.isError is True
567 | assert 'not allowed without write access' in result.content[0].text
568 | assert result.database_name == 'test-db'
569 | assert result.table_name == ''
570 | assert result.operation == 'create-table'
571 |
572 | @pytest.mark.asyncio
573 | async def test_manage_aws_glue_data_catalog_tables_get_read_access(
574 | self, handler, mock_ctx, mock_table_manager
575 | ):
576 | """Test that get table operation is allowed with read access."""
577 | from unittest.mock import ANY
578 |
579 | # Setup the mock to return a response
580 | expected_response = MagicMock()
581 | expected_response.isError = False
582 | expected_response.content = []
583 | expected_response.database_name = 'test-db'
584 | expected_response.table_name = 'test-table'
585 | expected_response.table_definition = {}
586 | expected_response.creation_time = '2023-01-01T00:00:00Z'
587 | expected_response.last_access_time = '2023-01-01T00:00:00Z'
588 | expected_response.operation = 'get'
589 | mock_table_manager.get_table.return_value = expected_response
590 |
591 | # Call the method with a read operation
592 | result = await handler.manage_aws_glue_data_catalog_tables(
593 | mock_ctx, operation='get-table', database_name='test-db', table_name='test-table'
594 | )
595 |
596 | # Verify that the method was called with the correct parameters
597 | # Use ANY for catalog_id to handle the FieldInfo object
598 | mock_table_manager.get_table.assert_called_once_with(
599 | ctx=mock_ctx, database_name='test-db', table_name='test-table', catalog_id=ANY
600 | )
601 |
602 | # Verify that the result is the expected response
603 | assert result == expected_response
604 |
605 | # Tests for manage_aws_glue_data_catalog_connections method
606 |
607 | @pytest.mark.asyncio
608 | async def test_manage_aws_glue_data_catalog_connections_create_no_write_access(
609 | self, handler, mock_ctx
610 | ):
611 | """Test that create connection operation is not allowed without write access."""
612 | # Call the method with a write operation
613 | result = await handler.manage_aws_glue_data_catalog_connections(
614 | mock_ctx,
615 | operation='create-connection',
616 | connection_name='test-connection',
617 | connection_input={},
618 | )
619 |
620 | # Verify that the result is an error response
621 | assert result.isError is True
622 | assert 'not allowed without write access' in result.content[0].text
623 | assert result.connection_name == ''
624 | assert result.operation == 'create-connection'
625 |
626 | @pytest.mark.asyncio
627 | async def test_manage_aws_glue_data_catalog_connections_get_read_access(
628 | self, handler, mock_ctx, mock_catalog_manager
629 | ):
630 | """Test that get connection operation is allowed with read access."""
631 | from unittest.mock import ANY
632 |
633 | # Setup the mock to return a response
634 | expected_response = MagicMock()
635 | expected_response.isError = False
636 | expected_response.content = []
637 | expected_response.connection_name = 'test-connection'
638 | expected_response.connection_type = 'JDBC'
639 | expected_response.connection_properties = {}
640 | expected_response.physical_connection_requirements = None
641 | expected_response.creation_time = '2023-01-01T00:00:00Z'
642 | expected_response.last_updated_time = '2023-01-01T00:00:00Z'
643 | expected_response.last_updated_by = ''
644 | expected_response.status = ''
645 | expected_response.status_reason = ''
646 | expected_response.last_connection_validation_time = ''
647 | expected_response.catalog_id = ''
648 | expected_response.operation = 'get'
649 | mock_catalog_manager.get_connection.return_value = expected_response
650 |
651 | # Call the method with a read operation
652 | result = await handler.manage_aws_glue_data_catalog_connections(
653 | mock_ctx, operation='get-connection', connection_name='test-connection'
654 | )
655 |
656 | # Verify that the method was called with the correct parameters
657 | # Use ANY for catalog_id to handle the FieldInfo object
658 | mock_catalog_manager.get_connection.assert_called_once_with(
659 | ctx=mock_ctx, connection_name='test-connection', catalog_id=ANY, hide_password=ANY
660 | )
661 |
662 | # Verify that the result is the expected response
663 | assert result == expected_response
664 |
665 | # Tests for manage_aws_glue_data_catalog_partitions method
666 |
667 | @pytest.mark.asyncio
668 | async def test_manage_aws_glue_data_catalog_partitions_create_no_write_access(
669 | self, handler, mock_ctx
670 | ):
671 | """Test that create partition operation is not allowed without write access."""
672 | # Call the method with a write operation
673 | result = await handler.manage_aws_glue_data_catalog_partitions(
674 | mock_ctx,
675 | operation='create-partition',
676 | database_name='test-db',
677 | table_name='test-table',
678 | partition_values=['2023'],
679 | partition_input={},
680 | )
681 |
682 | # Verify that the result is an error response
683 | assert result.isError is True
684 | assert 'not allowed without write access' in result.content[0].text
685 | assert result.database_name == 'test-db'
686 | assert result.table_name == 'test-table'
687 | assert result.partition_values == []
688 | assert result.operation == 'create-partition'
689 |
690 | @pytest.mark.asyncio
691 | async def test_manage_aws_glue_data_catalog_partitions_get_read_access(
692 | self, handler, mock_ctx, mock_catalog_manager
693 | ):
694 | """Test that get partition operation is allowed with read access."""
695 | from unittest.mock import ANY
696 |
697 | # Setup the mock to return a response
698 | expected_response = MagicMock()
699 | expected_response.isError = False
700 | expected_response.content = []
701 | expected_response.database_name = 'test-db'
702 | expected_response.table_name = 'test-table'
703 | expected_response.partition_values = ['2023']
704 | expected_response.partition_definition = {}
705 | expected_response.creation_time = '2023-01-01T00:00:00Z'
706 | expected_response.last_access_time = '2023-01-01T00:00:00Z'
707 | expected_response.operation = 'get'
708 | mock_catalog_manager.get_partition.return_value = expected_response
709 |
710 | # Call the method with a read operation
711 | result = await handler.manage_aws_glue_data_catalog_partitions(
712 | mock_ctx,
713 | operation='get-partition',
714 | database_name='test-db',
715 | table_name='test-table',
716 | partition_values=['2023'],
717 | )
718 |
719 | # Verify that the method was called with the correct parameters
720 | # Use ANY for catalog_id to handle the FieldInfo object
721 | mock_catalog_manager.get_partition.assert_called_once_with(
722 | ctx=mock_ctx,
723 | database_name='test-db',
724 | table_name='test-table',
725 | partition_values=['2023'],
726 | catalog_id=ANY,
727 | )
728 |
729 | # Verify that the result is the expected response
730 | assert result == expected_response
731 |
732 | # Tests for manage_aws_glue_data_catalog method
733 |
734 | @pytest.mark.asyncio
735 | async def test_manage_aws_glue_data_catalog_create_no_write_access(self, handler, mock_ctx):
736 | """Test that create catalog operation is not allowed without write access."""
737 | # Call the method with a write operation
738 | result = await handler.manage_aws_glue_data_catalog(
739 | mock_ctx, operation='create-catalog', catalog_id='test-catalog', catalog_input={}
740 | )
741 |
742 | # Verify that the result is an error response
743 | assert result.isError is True
744 | assert 'not allowed without write access' in result.content[0].text
745 | assert result.catalog_id == ''
746 | assert result.operation == 'create-catalog'
747 |
748 | @pytest.mark.asyncio
749 | async def test_manage_aws_glue_data_catalog_get_read_access(
750 | self, handler, mock_ctx, mock_catalog_manager
751 | ):
752 | """Test that get catalog operation is allowed with read access."""
753 | # Setup the mock to return a response
754 | expected_response = MagicMock()
755 | expected_response.isError = False
756 | expected_response.content = []
757 | expected_response.catalog_id = 'test-catalog'
758 | expected_response.catalog_definition = {}
759 | expected_response.name = 'Test Catalog'
760 | expected_response.description = 'Test catalog description'
761 | expected_response.create_time = '2023-01-01T00:00:00Z'
762 | expected_response.update_time = '2023-01-01T00:00:00Z'
763 | expected_response.operation = 'get'
764 | mock_catalog_manager.get_catalog.return_value = expected_response
765 |
766 | # Call the method with a read operation
767 | result = await handler.manage_aws_glue_data_catalog(
768 | mock_ctx, operation='get-catalog', catalog_id='test-catalog'
769 | )
770 |
771 | # Verify that the method was called with the correct parameters
772 | mock_catalog_manager.get_catalog.assert_called_once_with(
773 | ctx=mock_ctx, catalog_id='test-catalog'
774 | )
775 |
776 | # Verify that the result is the expected response
777 | assert result == expected_response
778 |
779 | @pytest.mark.asyncio
780 | async def test_manage_aws_glue_data_catalog_create_with_write_access(
781 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
782 | ):
783 | """Test that create catalog operation is allowed with write access."""
784 | # Setup the mock to return a response
785 | expected_response = MagicMock()
786 | expected_response.isError = False
787 | expected_response.content = []
788 | expected_response.catalog_id = 'test-catalog'
789 | expected_response.operation = 'create-catalog'
790 | mock_catalog_manager.create_catalog.return_value = expected_response
791 |
792 | # Call the method with a write operation
793 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
794 | mock_ctx,
795 | operation='create-catalog',
796 | catalog_id='test-catalog',
797 | catalog_input={'Description': 'Test catalog', 'Type': 'GLUE'},
798 | )
799 |
800 | # Verify that the method was called with the correct parameters
801 | mock_catalog_manager.create_catalog.assert_called_once_with(
802 | ctx=mock_ctx,
803 | catalog_name='test-catalog',
804 | catalog_input={'Description': 'Test catalog', 'Type': 'GLUE'},
805 | )
806 |
807 | # Verify that the result is the expected response
808 | assert result == expected_response
809 |
810 | @pytest.mark.asyncio
811 | async def test_manage_aws_glue_data_catalog_delete_with_write_access(
812 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
813 | ):
814 | """Test that delete catalog operation is allowed with write access."""
815 | # Setup the mock to return a response
816 | expected_response = MagicMock()
817 | expected_response.isError = False
818 | expected_response.content = []
819 | expected_response.catalog_id = 'test-catalog'
820 | expected_response.operation = 'delete-catalog'
821 | mock_catalog_manager.delete_catalog.return_value = expected_response
822 |
823 | # Call the method with a write operation
824 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
825 | mock_ctx, operation='delete-catalog', catalog_id='test-catalog'
826 | )
827 |
828 | # Verify that the method was called with the correct parameters
829 | mock_catalog_manager.delete_catalog.assert_called_once_with(
830 | ctx=mock_ctx, catalog_id='test-catalog'
831 | )
832 |
833 | # Verify that the result is the expected response
834 | assert result == expected_response
835 |
836 | @pytest.mark.asyncio
837 | async def test_manage_aws_glue_data_catalog_invalid_operation(self, handler, mock_ctx):
838 | """Test that an invalid operation returns an error response."""
839 | # Set write access to true to bypass the "not allowed without write access" check
840 | handler.allow_write = True
841 |
842 | # Call the method with an invalid operation
843 | result = await handler.manage_aws_glue_data_catalog(
844 | mock_ctx, operation='invalid-operation', catalog_id='test-catalog'
845 | )
846 |
847 | # Verify that the result is an error response
848 | assert result.isError is True
849 | assert 'Invalid operation' in result.content[0].text
850 | assert result.catalog_id == ''
851 | assert result.operation == 'get-catalog'
852 |
853 | @pytest.mark.asyncio
854 | async def test_manage_aws_glue_data_catalog_list_catalogs(self, handler, mock_ctx):
855 | """Test that list_catalogs operation returns a not implemented error."""
856 | # Call the method with list-catalogs operation
857 | mock_response = MagicMock()
858 | mock_response.isError = False
859 | mock_response.content = []
860 | mock_response.catalogs = []
861 | mock_response.count = 0
862 | mock_response.catalog_id = '123456789012'
863 | mock_response.operation = 'list-catalogs'
864 | handler.data_catalog_manager.list_catalogs.return_value = mock_response
865 | result = await handler.manage_aws_glue_data_catalog(mock_ctx, operation='list-catalogs')
866 |
867 | assert result.isError is False
868 | assert result.operation == 'list-catalogs'
869 |
870 | @pytest.mark.asyncio
871 | async def test_manage_aws_glue_data_catalog_list_catalogs_error(self, handler, mock_ctx):
872 | """Test that list_catalogs operation returns a not implemented error."""
873 | with patch.object(
874 | handler.data_catalog_manager,
875 | 'list_catalogs',
876 | side_effect=Exception('Invalid next_token provided'),
877 | ):
878 | with pytest.raises(Exception) as e:
879 | result = await handler.manage_aws_glue_data_catalog(
880 | mock_ctx, operation='list-catalogs'
881 | )
882 |
883 | assert result.isError is False
884 | assert result.operation == 'list-catalogs'
885 | assert 'Invalid next_token provided' in str(e)
886 |
887 | @pytest.mark.asyncio
888 | async def test_manage_aws_glue_data_catalog_import_catalog_with_read_only_access(
889 | self, handler, mock_ctx
890 | ):
891 | """Test that import_catalog_to_glue operation returns a not implemented error."""
892 | # Call the method with import-catalog-to-glue operation
893 | result = await handler.manage_aws_glue_data_catalog(
894 | mock_ctx,
895 | operation='import-catalog-to-glue',
896 | catalog_id='test-catalog',
897 | )
898 |
899 | assert result.isError is True
900 | assert result.operation == 'import-catalog-to-glue'
901 |
902 | @pytest.mark.asyncio
903 | async def test_manage_aws_glue_data_catalog_import_catalog(
904 | self, handler_with_write_access, mock_ctx
905 | ):
906 | """Test that import_catalog_to_glue operation returns a not implemented error."""
907 | # Call the method with import-catalog-to-glue operation
908 | mock_response = MagicMock()
909 | mock_response.isError = False
910 | mock_response.content = []
911 | mock_response.catalog_id = '123456789012'
912 | mock_response.operation = 'import-catalog-to-glue'
913 | handler_with_write_access.data_catalog_manager.import_catalog_to_glue.return_value = (
914 | mock_response
915 | )
916 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
917 | mock_ctx,
918 | operation='import-catalog-to-glue',
919 | catalog_id='test-catalog',
920 | )
921 |
922 | assert result.isError is False
923 | assert result.operation == 'import-catalog-to-glue'
924 |
925 | @pytest.mark.asyncio
926 | async def test_manage_aws_glue_data_catalog_missing_catalog_id(
927 | self, handler_with_write_access, mock_ctx
928 | ):
929 | """Test that missing catalog_id parameter causes an error."""
930 | # Mock the error response
931 | error_response = MagicMock()
932 | error_response.isError = True
933 | error_response.catalog_id = ''
934 | error_response.operation = 'create-catalog'
935 |
936 | # Mock the create_catalog method to return the error response
937 | handler_with_write_access.data_catalog_manager.create_catalog.return_value = error_response
938 |
939 | # Call the method without catalog_id
940 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
941 | mock_ctx, operation='create-catalog', catalog_input={}, catalog_id='123456'
942 | )
943 |
944 | # Verify that the result is the expected error response
945 | assert result == error_response
946 |
947 | @pytest.mark.asyncio
948 | async def test_manage_aws_glue_data_catalog_exception_handling(
949 | self, handler, mock_ctx, mock_catalog_manager
950 | ):
951 | """Test that exceptions are handled correctly in manage_aws_glue_data_catalog."""
952 | # Setup the mock to raise an exception
953 | mock_catalog_manager.get_catalog.side_effect = Exception('Test exception')
954 |
955 | # Call the method
956 | result = await handler.manage_aws_glue_data_catalog(
957 | mock_ctx, operation='get-catalog', catalog_id='test-catalog'
958 | )
959 |
960 | # Verify that the result is an error response
961 | assert result.isError is True
962 | assert 'Error in manage_aws_glue_data_catalog' in result.content[0].text
963 | assert 'Test exception' in result.content[0].text
964 | assert result.catalog_id == 'test-catalog'
965 | assert result.operation == 'get-catalog'
966 |
967 | @pytest.mark.asyncio
968 | async def test_manage_aws_glue_data_catalog_tables_list_tables_error(
969 | self, handler_with_write_access, mock_ctx, mock_table_manager
970 | ):
971 | """Test that list_tables handles errors correctly."""
972 | # Setup the mock to raise an exception
973 | mock_table_manager.list_tables.side_effect = Exception('Test exception')
974 |
975 | # Call the method
976 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
977 | mock_ctx, operation='list-tables', database_name='test-db'
978 | )
979 |
980 | # Verify that the result is an error response
981 | assert result.isError is True
982 | assert any(
983 | 'Error in manage_aws_glue_data_catalog_tables: Test exception' in content.text
984 | for content in result.content
985 | )
986 | assert result.database_name == 'test-db'
987 | assert result.table_name == '' # Empty string for table_name in error responses
988 | assert result.operation == 'get-table'
989 |
990 | @pytest.mark.asyncio
991 | async def test_manage_aws_glue_data_catalog_tables_search_tables_error(
992 | self, handler_with_write_access, mock_ctx, mock_table_manager
993 | ):
994 | """Test that search_tables handles errors correctly."""
995 | # Setup the mock to raise an exception
996 | mock_table_manager.search_tables.side_effect = Exception('Test exception')
997 |
998 | # Call the method
999 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1000 | mock_ctx, operation='search-tables', database_name='test-db', search_text='test'
1001 | )
1002 |
1003 | # Verify that the result is an error response
1004 | assert result.isError is True
1005 | assert any(
1006 | 'Error in manage_aws_glue_data_catalog_tables: Test exception' in content.text
1007 | for content in result.content
1008 | )
1009 | assert result.database_name == 'test-db'
1010 | assert result.table_name == '' # Empty string for table_name in error responses
1011 | assert result.operation == 'get-table'
1012 |
1013 | @pytest.mark.asyncio
1014 | async def test_manage_aws_glue_data_catalog_tables_missing_table_name(
1015 | self, handler_with_write_access, mock_ctx
1016 | ):
1017 | """Test that missing table_name parameter causes an error."""
1018 | # Call the method without table_name
1019 | with pytest.raises(ValueError) as excinfo:
1020 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1021 | mock_ctx, operation='get-table', database_name='test-db', table_name=None
1022 | )
1023 |
1024 | # Verify that the correct error message is raised
1025 | assert 'table_name is required' in str(excinfo.value)
1026 |
1027 | @pytest.mark.asyncio
1028 | async def test_manage_aws_glue_data_catalog_connections_list_connections_error(
1029 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1030 | ):
1031 | """Test that list_connections handles errors correctly."""
1032 | # Setup the mock to raise an exception
1033 | mock_catalog_manager.list_connections.side_effect = Exception('Test exception')
1034 |
1035 | # Call the method
1036 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1037 | mock_ctx, operation='list-connections'
1038 | )
1039 |
1040 | # Verify that the result is an error response
1041 | assert result.isError is True
1042 | assert any(
1043 | 'Error in manage_aws_glue_data_catalog_connections: Test exception' in content.text
1044 | for content in result.content
1045 | )
1046 | assert result.connection_name == '' # Empty string for connection_name in error responses
1047 | assert result.catalog_id == '' # Empty string for catalog_id in error responses
1048 | assert result.operation == 'get-connection'
1049 |
1050 | @pytest.mark.asyncio
1051 | async def test_manage_aws_glue_data_catalog_connections_missing_connection_name(
1052 | self, handler_with_write_access, mock_ctx
1053 | ):
1054 | """Test that missing connection_name parameter causes an error."""
1055 | # Mock the ValueError that should be raised
1056 | with patch.object(
1057 | handler_with_write_access.data_catalog_manager,
1058 | 'get_connection',
1059 | side_effect=ValueError('connection_name is required for get operation'),
1060 | ):
1061 | # Call the method without connection_name
1062 | with pytest.raises(ValueError) as excinfo:
1063 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1064 | mock_ctx, operation='get-connection'
1065 | )
1066 |
1067 | # Verify that the correct error message is raised
1068 | assert 'connection_name is required' in str(excinfo.value)
1069 |
1070 | @pytest.mark.asyncio
1071 | async def test_manage_aws_glue_data_catalog_partitions_list_partitions_error(
1072 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1073 | ):
1074 | """Test that list_partitions handles errors correctly."""
1075 | # Setup the mock to raise an exception
1076 | mock_catalog_manager.list_partitions.side_effect = Exception('Test exception')
1077 |
1078 | # Call the method
1079 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1080 | mock_ctx, operation='list-partitions', database_name='test-db', table_name='test-table'
1081 | )
1082 |
1083 | # Verify that the result is an error response
1084 | assert result.isError is True
1085 | assert any(
1086 | 'Error in manage_aws_glue_data_catalog_partitions: Test exception' in content.text
1087 | for content in result.content
1088 | )
1089 | assert result.database_name == 'test-db'
1090 | assert result.table_name == 'test-table'
1091 | assert result.partition_values == [] # Empty list for partition_values in error responses
1092 | assert result.operation == 'get-partition'
1093 |
1094 | @pytest.mark.asyncio
1095 | async def test_manage_aws_glue_data_catalog_partitions_missing_partition_values(
1096 | self, handler_with_write_access, mock_ctx
1097 | ):
1098 | """Test that missing partition_values parameter causes an error."""
1099 | # Mock the ValueError that should be raised
1100 | with patch.object(
1101 | handler_with_write_access.data_catalog_manager,
1102 | 'get_partition',
1103 | side_effect=ValueError('partition_values is required for get-partition operation'),
1104 | ):
1105 | # Call the method without partition_values
1106 | with pytest.raises(ValueError) as excinfo:
1107 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1108 | mock_ctx,
1109 | operation='get-partition',
1110 | database_name='test-db',
1111 | table_name='test-table',
1112 | )
1113 |
1114 | # Verify that the correct error message is raised
1115 | assert 'partition_values is required' in str(excinfo.value)
1116 |
1117 | @pytest.mark.asyncio
1118 | async def test_manage_aws_glue_data_catalog_tables_delete_no_write_access(
1119 | self, handler, mock_ctx
1120 | ):
1121 | """Test that delete table operation is not allowed without write access."""
1122 | # Call the method with a write operation
1123 | result = await handler.manage_aws_glue_data_catalog_tables(
1124 | mock_ctx,
1125 | operation='delete-table',
1126 | database_name='test-db',
1127 | table_name='test-table',
1128 | )
1129 |
1130 | # Verify that the result is an error response
1131 | assert result.isError is True
1132 | assert 'not allowed without write access' in result.content[0].text
1133 | assert result.database_name == 'test-db'
1134 | assert result.table_name == ''
1135 | assert result.operation == 'delete-table'
1136 |
1137 | @pytest.mark.asyncio
1138 | async def test_manage_aws_glue_data_catalog_connections_delete_no_write_access(
1139 | self, handler, mock_ctx
1140 | ):
1141 | """Test that delete connection operation is not allowed without write access."""
1142 | # Call the method with a write operation
1143 | result = await handler.manage_aws_glue_data_catalog_connections(
1144 | mock_ctx, operation='delete-connection', connection_name='test-connection'
1145 | )
1146 |
1147 | # Verify that the result is an error response
1148 | assert result.isError is True
1149 | assert 'not allowed without write access' in result.content[0].text
1150 | assert result.connection_name == ''
1151 | assert result.operation == 'delete-connection'
1152 |
1153 | @pytest.mark.asyncio
1154 | async def test_manage_aws_glue_data_catalog_connections_update_no_write_access(
1155 | self, handler, mock_ctx
1156 | ):
1157 | """Test that update connection operation is not allowed without write access."""
1158 | # Call the method with a write operation
1159 | result = await handler.manage_aws_glue_data_catalog_connections(
1160 | mock_ctx,
1161 | operation='update-connection',
1162 | connection_name='test-connection',
1163 | connection_input={},
1164 | )
1165 |
1166 | # Verify that the result is an error response
1167 | assert result.isError is True
1168 | assert 'not allowed without write access' in result.content[0].text
1169 | assert result.connection_name == ''
1170 | assert result.operation == 'update-connection'
1171 |
1172 | @pytest.mark.asyncio
1173 | async def test_manage_aws_glue_data_catalog_partitions_delete_no_write_access(
1174 | self, handler, mock_ctx
1175 | ):
1176 | """Test that delete partition operation is not allowed without write access."""
1177 | # Call the method with a write operation
1178 | result = await handler.manage_aws_glue_data_catalog_partitions(
1179 | mock_ctx,
1180 | operation='delete-partition',
1181 | database_name='test-db',
1182 | table_name='test-table',
1183 | partition_values=['2023'],
1184 | )
1185 |
1186 | # Verify that the result is an error response
1187 | assert result.isError is True
1188 | assert 'not allowed without write access' in result.content[0].text
1189 | assert result.database_name == 'test-db'
1190 | assert result.table_name == 'test-table'
1191 | assert result.partition_values == []
1192 | assert result.operation == 'delete-partition'
1193 |
1194 | @pytest.mark.asyncio
1195 | async def test_manage_aws_glue_data_catalog_partitions_update_no_write_access(
1196 | self, handler, mock_ctx
1197 | ):
1198 | """Test that update partition operation is not allowed without write access."""
1199 | # Call the method with a write operation
1200 | result = await handler.manage_aws_glue_data_catalog_partitions(
1201 | mock_ctx,
1202 | operation='update-partition',
1203 | database_name='test-db',
1204 | table_name='test-table',
1205 | partition_values=['2023'],
1206 | partition_input={},
1207 | )
1208 |
1209 | # Verify that the result is an error response
1210 | assert result.isError is True
1211 | assert 'not allowed without write access' in result.content[0].text
1212 | assert result.database_name == 'test-db'
1213 | assert result.table_name == 'test-table'
1214 | assert result.partition_values == []
1215 | assert result.operation == 'update-partition'
1216 |
1217 | @pytest.mark.asyncio
1218 | async def test_manage_aws_glue_data_catalog_delete_no_write_access(self, handler, mock_ctx):
1219 | """Test that delete catalog operation is not allowed without write access."""
1220 | # Call the method with a write operation
1221 | result = await handler.manage_aws_glue_data_catalog(
1222 | mock_ctx, operation='delete-catalog', catalog_id='test-catalog'
1223 | )
1224 |
1225 | # Verify that the result is an error response
1226 | assert result.isError is True
1227 | assert 'not allowed without write access' in result.content[0].text
1228 | assert result.catalog_id == ''
1229 | assert result.operation == 'delete-catalog'
1230 |
1231 | @pytest.mark.asyncio
1232 | async def test_manage_aws_glue_data_catalog_databases_with_all_parameters(
1233 | self, handler_with_write_access, mock_ctx, mock_database_manager
1234 | ):
1235 | """Test that all parameters are passed correctly to the database manager."""
1236 | # Setup the mock to return a response
1237 | expected_response = MagicMock()
1238 | expected_response.isError = False
1239 | expected_response.content = []
1240 | expected_response.database_name = 'test-db'
1241 | expected_response.operation = 'create'
1242 | mock_database_manager.create_database.return_value = expected_response
1243 |
1244 | # Call the method with all parameters
1245 | result = await handler_with_write_access.manage_aws_glue_data_catalog_databases(
1246 | mock_ctx,
1247 | operation='create-database',
1248 | database_name='test-db',
1249 | description='Test database',
1250 | location_uri='s3://test-bucket/',
1251 | parameters={'key1': 'value1', 'key2': 'value2'},
1252 | catalog_id='123456789012',
1253 | )
1254 |
1255 | # Verify that the method was called with the correct parameters
1256 | mock_database_manager.create_database.assert_called_once()
1257 | assert mock_database_manager.create_database.call_args[1]['database_name'] == 'test-db'
1258 | assert mock_database_manager.create_database.call_args[1]['description'] == 'Test database'
1259 | assert (
1260 | mock_database_manager.create_database.call_args[1]['location_uri']
1261 | == 's3://test-bucket/'
1262 | )
1263 | assert mock_database_manager.create_database.call_args[1]['parameters'] == {
1264 | 'key1': 'value1',
1265 | 'key2': 'value2',
1266 | }
1267 | assert mock_database_manager.create_database.call_args[1]['catalog_id'] == '123456789012'
1268 |
1269 | # Verify that the result is the expected response
1270 | assert result == expected_response
1271 |
1272 | @pytest.mark.asyncio
1273 | async def test_manage_aws_glue_data_catalog_tables_with_short_operation_names(
1274 | self, handler_with_write_access, mock_ctx, mock_table_manager
1275 | ):
1276 | """Test that short operation names (create, delete, etc.) work correctly for tables."""
1277 | # Setup the mock to return a response
1278 | expected_response = MagicMock()
1279 | expected_response.isError = False
1280 | expected_response.content = []
1281 | expected_response.database_name = 'test-db'
1282 | expected_response.table_name = 'test-table'
1283 | expected_response.operation = 'create-table'
1284 | mock_table_manager.create_table.return_value = expected_response
1285 |
1286 | # Call the method with a short operation name
1287 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1288 | mock_ctx,
1289 | operation='create-table', # Short form of 'create-table'
1290 | database_name='test-db',
1291 | table_name='test-table',
1292 | table_input={'Name': 'test-table'},
1293 | )
1294 |
1295 | # Verify that the method was called with the correct parameters
1296 | mock_table_manager.create_table.assert_called_once()
1297 | assert mock_table_manager.create_table.call_args[1]['database_name'] == 'test-db'
1298 | assert mock_table_manager.create_table.call_args[1]['table_name'] == 'test-table'
1299 | assert mock_table_manager.create_table.call_args[1]['table_input'] == {
1300 | 'Name': 'test-table'
1301 | }
1302 |
1303 | # Verify that the result is the expected response
1304 | assert result == expected_response
1305 |
1306 | @pytest.mark.asyncio
1307 | async def test_manage_aws_glue_data_catalog_tables_search_with_short_operation_name(
1308 | self, handler, mock_ctx, mock_table_manager
1309 | ):
1310 | """Test that search operation with short name works correctly for tables."""
1311 | # Setup the mock to return a response
1312 | expected_response = MagicMock()
1313 | expected_response.isError = False
1314 | expected_response.content = []
1315 | expected_response.tables = []
1316 | expected_response.search_text = 'test'
1317 | expected_response.count = 0
1318 | expected_response.operation = 'search-tables'
1319 | mock_table_manager.search_tables.return_value = expected_response
1320 |
1321 | # Call the method with a short operation name
1322 | result = await handler.manage_aws_glue_data_catalog_tables(
1323 | mock_ctx,
1324 | operation='search-tables', # Short form of 'search-tables'
1325 | database_name='test-db',
1326 | search_text='test',
1327 | )
1328 |
1329 | # Verify that the method was called with the correct parameters
1330 | mock_table_manager.search_tables.assert_called_once()
1331 | assert mock_table_manager.search_tables.call_args[1]['search_text'] == 'test'
1332 |
1333 | # Verify that the result is the expected response
1334 | assert result == expected_response
1335 |
1336 | @pytest.mark.asyncio
1337 | async def test_manage_aws_glue_data_catalog_connections_with_short_operation_names(
1338 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1339 | ):
1340 | """Test that short operation names (create, delete, etc.) work correctly for connections."""
1341 | # Setup the mock to return a response
1342 | expected_response = MagicMock()
1343 | expected_response.isError = False
1344 | expected_response.content = []
1345 | expected_response.connection_name = 'test-connection'
1346 | expected_response.operation = 'create-connection'
1347 | mock_catalog_manager.create_connection.return_value = expected_response
1348 |
1349 | # Call the method with a short operation name
1350 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1351 | mock_ctx,
1352 | operation='create-connection', # Short form of 'create-connection'
1353 | connection_name='test-connection',
1354 | connection_input={'ConnectionType': 'JDBC'},
1355 | )
1356 |
1357 | # Verify that the method was called with the correct parameters
1358 | mock_catalog_manager.create_connection.assert_called_once()
1359 | assert (
1360 | mock_catalog_manager.create_connection.call_args[1]['connection_name']
1361 | == 'test-connection'
1362 | )
1363 | assert mock_catalog_manager.create_connection.call_args[1]['connection_input'] == {
1364 | 'ConnectionType': 'JDBC'
1365 | }
1366 |
1367 | # Verify that the result is the expected response
1368 | assert result == expected_response
1369 |
1370 | @pytest.mark.asyncio
1371 | async def test_manage_aws_glue_data_catalog_partitions_with_short_operation_names(
1372 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1373 | ):
1374 | """Test that short operation names (create, delete, etc.) work correctly for partitions."""
1375 | # Setup the mock to return a response
1376 | expected_response = MagicMock()
1377 | expected_response.isError = False
1378 | expected_response.content = []
1379 | expected_response.database_name = 'test-db'
1380 | expected_response.table_name = 'test-table'
1381 | expected_response.partition_values = ['2023']
1382 | expected_response.operation = 'create-partition'
1383 | mock_catalog_manager.create_partition.return_value = expected_response
1384 |
1385 | # Call the method with a short operation name
1386 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1387 | mock_ctx,
1388 | operation='create-partition', # Short form of 'create-partition'
1389 | database_name='test-db',
1390 | table_name='test-table',
1391 | partition_values=['2023'],
1392 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023'}},
1393 | )
1394 |
1395 | # Verify that the method was called with the correct parameters
1396 | mock_catalog_manager.create_partition.assert_called_once()
1397 | assert mock_catalog_manager.create_partition.call_args[1]['database_name'] == 'test-db'
1398 | assert mock_catalog_manager.create_partition.call_args[1]['table_name'] == 'test-table'
1399 | assert mock_catalog_manager.create_partition.call_args[1]['partition_values'] == ['2023']
1400 | assert mock_catalog_manager.create_partition.call_args[1]['partition_input'] == {
1401 | 'StorageDescriptor': {'Location': 's3://bucket/path/2023'}
1402 | }
1403 |
1404 | # Verify that the result is the expected response
1405 | assert result == expected_response
1406 |
1407 | @pytest.mark.asyncio
1408 | async def test_manage_aws_glue_data_catalog_with_short_operation_names(
1409 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1410 | ):
1411 | """Test that short operation names (create, delete, etc.) work correctly for catalog."""
1412 | # Setup the mock to return a response
1413 | expected_response = MagicMock()
1414 | expected_response.isError = False
1415 | expected_response.content = []
1416 | expected_response.catalog_id = 'test-catalog'
1417 | expected_response.operation = 'create-catalog'
1418 | mock_catalog_manager.create_catalog.return_value = expected_response
1419 |
1420 | # Call the method with a short operation name
1421 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
1422 | mock_ctx,
1423 | operation='create-catalog', # Short form of 'create-catalog'
1424 | catalog_id='test-catalog',
1425 | catalog_input={'Description': 'Test catalog'},
1426 | )
1427 |
1428 | # Verify that the method was called with the correct parameters
1429 | mock_catalog_manager.create_catalog.assert_called_once()
1430 | assert mock_catalog_manager.create_catalog.call_args[1]['catalog_name'] == 'test-catalog'
1431 | assert mock_catalog_manager.create_catalog.call_args[1]['catalog_input'] == {
1432 | 'Description': 'Test catalog'
1433 | }
1434 |
1435 | # Verify that the result is the expected response
1436 | assert result == expected_response
1437 |
1438 | @pytest.mark.asyncio
1439 | async def test_manage_aws_glue_data_catalog_tables_create_missing_table_input(
1440 | self, handler_with_write_access, mock_ctx
1441 | ):
1442 | """Test that missing table_input parameter for create-table operation raises a ValueError."""
1443 | # Mock the data_catalog_table_manager to raise the expected ValueError
1444 | handler_with_write_access.data_catalog_table_manager.create_table.side_effect = ValueError(
1445 | 'table_name and table_input are required for create-table operation'
1446 | )
1447 |
1448 | # Call the method without table_input
1449 | with pytest.raises(ValueError) as excinfo:
1450 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1451 | mock_ctx,
1452 | operation='create-table',
1453 | database_name='test-db',
1454 | table_name='test-table',
1455 | )
1456 |
1457 | # Verify that the correct error message is raised
1458 | assert 'database_name, table_input and table_name are required' in str(excinfo.value)
1459 |
1460 | @pytest.mark.asyncio
1461 | async def test_manage_aws_glue_data_catalog_tables_update_missing_table_input(
1462 | self, handler_with_write_access, mock_ctx
1463 | ):
1464 | """Test that missing table_input parameter for update-table operation raises a ValueError."""
1465 | # Mock the data_catalog_table_manager to raise the expected ValueError
1466 | handler_with_write_access.data_catalog_table_manager.update_table.side_effect = ValueError(
1467 | 'table_name and table_input are required for update-table operation'
1468 | )
1469 |
1470 | # Call the method without table_input
1471 | with pytest.raises(ValueError) as excinfo:
1472 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1473 | mock_ctx,
1474 | operation='update-table',
1475 | database_name='test-db',
1476 | table_name='test-table',
1477 | )
1478 |
1479 | # Verify that the correct error message is raised
1480 | assert 'table_name and table_input are required' in str(excinfo.value)
1481 |
1482 | @pytest.mark.asyncio
1483 | async def test_manage_aws_glue_data_catalog_connections_create_missing_connection_input(
1484 | self, handler_with_write_access, mock_ctx
1485 | ):
1486 | """Test that missing connection_input parameter for create operation raises a ValueError."""
1487 | # Mock the data_catalog_manager to raise the expected ValueError
1488 | handler_with_write_access.data_catalog_manager.create_connection.side_effect = ValueError(
1489 | 'connection_name and connection_input are required for create operation'
1490 | )
1491 |
1492 | # Call the method without connection_input
1493 | with pytest.raises(ValueError) as excinfo:
1494 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1495 | mock_ctx,
1496 | operation='create-connection',
1497 | connection_name='test-connection',
1498 | )
1499 |
1500 | # Verify that the correct error message is raised
1501 | assert 'connection_name and connection_input are required' in str(excinfo.value)
1502 |
1503 | @pytest.mark.asyncio
1504 | async def test_manage_aws_glue_data_catalog_connections_update_missing_connection_input(
1505 | self, handler_with_write_access, mock_ctx
1506 | ):
1507 | """Test that missing connection_input parameter for update operation raises a ValueError."""
1508 | # Mock the data_catalog_manager to raise the expected ValueError
1509 | handler_with_write_access.data_catalog_manager.update_connection.side_effect = ValueError(
1510 | 'connection_name and connection_input are required for update operation'
1511 | )
1512 |
1513 | # Call the method without connection_input
1514 | with pytest.raises(ValueError) as excinfo:
1515 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1516 | mock_ctx,
1517 | operation='update-connection',
1518 | connection_name='test-connection',
1519 | )
1520 |
1521 | # Verify that the correct error message is raised
1522 | assert 'connection_name and connection_input are required' in str(excinfo.value)
1523 |
1524 | @pytest.mark.asyncio
1525 | async def test_manage_aws_glue_data_catalog_partitions_create_missing_partition_input(
1526 | self, handler_with_write_access, mock_ctx
1527 | ):
1528 | """Test that missing partition_input parameter for create-partition operation raises a ValueError."""
1529 | # Mock the data_catalog_manager to raise the expected ValueError
1530 | handler_with_write_access.data_catalog_manager.create_partition.side_effect = ValueError(
1531 | 'partition_values and partition_input are required for create-partition operation'
1532 | )
1533 |
1534 | # Call the method without partition_input
1535 | with pytest.raises(ValueError) as excinfo:
1536 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1537 | mock_ctx,
1538 | operation='create-partition',
1539 | database_name='test-db',
1540 | table_name='test-table',
1541 | partition_values=['2023'],
1542 | )
1543 |
1544 | # Verify that the correct error message is raised
1545 | assert 'partition_values and partition_input are required' in str(excinfo.value)
1546 |
1547 | @pytest.mark.asyncio
1548 | async def test_manage_aws_glue_data_catalog_partitions_update_missing_partition_input(
1549 | self, handler_with_write_access, mock_ctx
1550 | ):
1551 | """Test that missing partition_input parameter for update-partition operation raises a ValueError."""
1552 | # Mock the data_catalog_manager to raise the expected ValueError
1553 | handler_with_write_access.data_catalog_manager.update_partition.side_effect = ValueError(
1554 | 'partition_values and partition_input are required for update-partition operation'
1555 | )
1556 |
1557 | # Call the method without partition_input
1558 | with pytest.raises(ValueError) as excinfo:
1559 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1560 | mock_ctx,
1561 | operation='update-partition',
1562 | database_name='test-db',
1563 | table_name='test-table',
1564 | partition_values=['2023'],
1565 | )
1566 |
1567 | # Verify that the correct error message is raised
1568 | assert 'partition_values and partition_input are required' in str(excinfo.value)
1569 |
1570 | @pytest.mark.asyncio
1571 | async def test_manage_aws_glue_data_catalog_catalog_missing_catalog_input(
1572 | self, handler_with_write_access, mock_ctx
1573 | ):
1574 | """Test that missing catalog_input parameter for create-catalog operation raises a ValueError."""
1575 | # Mock the ValueError that should be raised
1576 | with patch.object(
1577 | handler_with_write_access.data_catalog_manager,
1578 | 'create_catalog',
1579 | side_effect=ValueError('catalog_input is required for create-catalog operation'),
1580 | ):
1581 | # Call the method without catalog_input
1582 | with pytest.raises(ValueError) as excinfo:
1583 | await handler_with_write_access.manage_aws_glue_data_catalog(
1584 | mock_ctx,
1585 | operation='create-catalog',
1586 | catalog_id='test-catalog',
1587 | )
1588 |
1589 | # Verify that the correct error message is raised
1590 | assert 'catalog_id and catalog_input are required' in str(excinfo.value)
1591 |
1592 | @pytest.mark.asyncio
1593 | async def test_manage_aws_glue_data_catalog_tables_create_with_table_input(
1594 | self, handler_with_write_access, mock_ctx, mock_table_manager
1595 | ):
1596 | """Test creating a table with a complete table input."""
1597 | # Setup the mock to return a response
1598 | expected_response = MagicMock()
1599 | expected_response.isError = False
1600 | expected_response.content = []
1601 | expected_response.database_name = 'test-db'
1602 | expected_response.table_name = 'test-table'
1603 | expected_response.operation = 'create-table'
1604 | mock_table_manager.create_table.return_value = expected_response
1605 |
1606 | # Create a comprehensive table input
1607 | table_input = {
1608 | 'Name': 'test-table',
1609 | 'Description': 'Test table for unit testing',
1610 | 'Owner': 'test-owner',
1611 | 'TableType': 'EXTERNAL_TABLE',
1612 | 'Parameters': {'classification': 'parquet', 'compressionType': 'snappy'},
1613 | 'StorageDescriptor': {
1614 | 'Columns': [
1615 | {'Name': 'id', 'Type': 'int'},
1616 | {'Name': 'name', 'Type': 'string'},
1617 | {'Name': 'timestamp', 'Type': 'timestamp'},
1618 | ],
1619 | 'Location': 's3://test-bucket/test-db/test-table/',
1620 | 'InputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat',
1621 | 'OutputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat',
1622 | 'Compressed': True,
1623 | 'SerdeInfo': {
1624 | 'SerializationLibrary': 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe',
1625 | 'Parameters': {'serialization.format': '1'},
1626 | },
1627 | },
1628 | 'PartitionKeys': [
1629 | {'Name': 'year', 'Type': 'string'},
1630 | {'Name': 'month', 'Type': 'string'},
1631 | ],
1632 | }
1633 |
1634 | # Call the method with the table input
1635 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1636 | mock_ctx,
1637 | operation='create-table',
1638 | database_name='test-db',
1639 | table_name='test-table',
1640 | table_input=table_input,
1641 | catalog_id='123456789012',
1642 | )
1643 |
1644 | # Verify that the method was called with the correct parameters
1645 | mock_table_manager.create_table.assert_called_once_with(
1646 | ctx=mock_ctx,
1647 | database_name='test-db',
1648 | table_name='test-table',
1649 | table_input=table_input,
1650 | catalog_id='123456789012',
1651 | )
1652 |
1653 | # Verify that the result is the expected response
1654 | assert result == expected_response
1655 |
1656 | @pytest.mark.asyncio
1657 | async def test_manage_aws_glue_data_catalog_tables_update_with_table_input(
1658 | self, handler_with_write_access, mock_ctx, mock_table_manager
1659 | ):
1660 | """Test updating a table with a complete table input."""
1661 | # Setup the mock to return a response
1662 | expected_response = MagicMock()
1663 | expected_response.isError = False
1664 | expected_response.content = []
1665 | expected_response.database_name = 'test-db'
1666 | expected_response.table_name = 'test-table'
1667 | expected_response.operation = 'update-table'
1668 | mock_table_manager.update_table.return_value = expected_response
1669 |
1670 | # Create a comprehensive table input for update
1671 | table_input = {
1672 | 'Name': 'test-table',
1673 | 'Description': 'Updated test table description',
1674 | 'Owner': 'updated-owner',
1675 | 'Parameters': {
1676 | 'classification': 'parquet',
1677 | 'compressionType': 'gzip', # Changed from snappy to gzip
1678 | 'updatedAt': '2023-01-01',
1679 | },
1680 | 'StorageDescriptor': {
1681 | 'Columns': [
1682 | {'Name': 'id', 'Type': 'int'},
1683 | {'Name': 'name', 'Type': 'string'},
1684 | {'Name': 'timestamp', 'Type': 'timestamp'},
1685 | {'Name': 'new_column', 'Type': 'string'}, # Added a new column
1686 | ],
1687 | 'Location': 's3://test-bucket/test-db/test-table/',
1688 | 'InputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat',
1689 | 'OutputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat',
1690 | 'Compressed': True,
1691 | 'SerdeInfo': {
1692 | 'SerializationLibrary': 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe',
1693 | 'Parameters': {'serialization.format': '1'},
1694 | },
1695 | },
1696 | }
1697 |
1698 | # Call the method with the table input
1699 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
1700 | mock_ctx,
1701 | operation='update-table',
1702 | database_name='test-db',
1703 | table_name='test-table',
1704 | table_input=table_input,
1705 | catalog_id='123456789012',
1706 | )
1707 |
1708 | # Verify that the method was called with the correct parameters
1709 | mock_table_manager.update_table.assert_called_once_with(
1710 | ctx=mock_ctx,
1711 | database_name='test-db',
1712 | table_name='test-table',
1713 | table_input=table_input,
1714 | catalog_id='123456789012',
1715 | )
1716 |
1717 | # Verify that the result is the expected response
1718 | assert result == expected_response
1719 |
1720 | @pytest.mark.asyncio
1721 | async def test_manage_aws_glue_data_catalog_connections_create_with_connection_input(
1722 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1723 | ):
1724 | """Test creating a connection with a complete connection input."""
1725 | # Setup the mock to return a response
1726 | expected_response = MagicMock()
1727 | expected_response.isError = False
1728 | expected_response.content = []
1729 | expected_response.connection_name = 'test-jdbc-connection'
1730 | expected_response.operation = 'create-connection'
1731 | expected_response.catalog_id = '123456789012'
1732 | mock_catalog_manager.create_connection.return_value = expected_response
1733 |
1734 | # Create a comprehensive connection input
1735 | connection_input = {
1736 | 'ConnectionType': 'JDBC',
1737 | 'ConnectionProperties': {
1738 | 'JDBC_CONNECTION_URL': 'jdbc:mysql://test-host:3306/test-db',
1739 | 'USERNAME': 'test-user',
1740 | 'PASSWORD': 'test-password', # pragma: allowlist secret
1741 | 'JDBC_ENFORCE_SSL': 'true',
1742 | },
1743 | 'PhysicalConnectionRequirements': {
1744 | 'AvailabilityZone': 'us-west-2a',
1745 | 'SecurityGroupIdList': ['sg-12345678'],
1746 | 'SubnetId': 'subnet-12345678',
1747 | },
1748 | 'Description': 'Test JDBC connection for unit testing',
1749 | }
1750 |
1751 | # Call the method with the connection input
1752 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1753 | mock_ctx,
1754 | operation='create-connection',
1755 | connection_name='test-jdbc-connection',
1756 | connection_input=connection_input,
1757 | catalog_id='123456789012',
1758 | )
1759 |
1760 | # Verify that the method was called with the correct parameters
1761 | mock_catalog_manager.create_connection.assert_called_once_with(
1762 | ctx=mock_ctx,
1763 | connection_name='test-jdbc-connection',
1764 | connection_input=connection_input,
1765 | catalog_id='123456789012',
1766 | )
1767 |
1768 | # Verify that the result is the expected response
1769 | assert result == expected_response
1770 | assert result.connection_name == 'test-jdbc-connection'
1771 | assert result.catalog_id == '123456789012'
1772 |
1773 | @pytest.mark.asyncio
1774 | async def test_manage_aws_glue_data_catalog_connections_update_with_connection_input(
1775 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1776 | ):
1777 | """Test updating a connection with a complete connection input."""
1778 | # Setup the mock to return a response
1779 | expected_response = MagicMock()
1780 | expected_response.isError = False
1781 | expected_response.content = []
1782 | expected_response.connection_name = 'test-jdbc-connection'
1783 | expected_response.operation = 'update-connection'
1784 | expected_response.catalog_id = '123456789012'
1785 | mock_catalog_manager.update_connection.return_value = expected_response
1786 |
1787 | # Create a comprehensive connection input for update
1788 | connection_input = {
1789 | 'ConnectionType': 'JDBC',
1790 | 'ConnectionProperties': {
1791 | 'JDBC_CONNECTION_URL': 'jdbc:mysql://updated-host:3306/updated-db',
1792 | 'USERNAME': 'updated-user',
1793 | 'PASSWORD': 'updated-password', # pragma: allowlist secret
1794 | 'JDBC_ENFORCE_SSL': 'true',
1795 | },
1796 | 'PhysicalConnectionRequirements': {
1797 | 'AvailabilityZone': 'us-west-2b', # Changed from us-west-2a
1798 | 'SecurityGroupIdList': ['sg-87654321'], # Changed security group
1799 | 'SubnetId': 'subnet-87654321', # Changed subnet
1800 | },
1801 | 'Description': 'Updated JDBC connection for unit testing',
1802 | }
1803 |
1804 | # Call the method with the connection input
1805 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
1806 | mock_ctx,
1807 | operation='update-connection',
1808 | connection_name='test-jdbc-connection',
1809 | connection_input=connection_input,
1810 | catalog_id='123456789012',
1811 | )
1812 |
1813 | # Verify that the method was called with the correct parameters
1814 | mock_catalog_manager.update_connection.assert_called_once_with(
1815 | ctx=mock_ctx,
1816 | connection_name='test-jdbc-connection',
1817 | connection_input=connection_input,
1818 | catalog_id='123456789012',
1819 | )
1820 |
1821 | # Verify that the result is the expected response
1822 | assert result == expected_response
1823 | assert result.connection_name == 'test-jdbc-connection'
1824 | assert result.catalog_id == '123456789012'
1825 |
1826 | @pytest.mark.asyncio
1827 | async def test_manage_aws_glue_data_catalog_partitions_create_with_partition_input(
1828 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1829 | ):
1830 | """Test creating a partition with a complete partition input."""
1831 | # Setup the mock to return a response
1832 | expected_response = MagicMock()
1833 | expected_response.isError = False
1834 | expected_response.content = []
1835 | expected_response.database_name = 'test-db'
1836 | expected_response.table_name = 'test-table'
1837 | expected_response.partition_values = ['2023', '01']
1838 | expected_response.operation = 'create-partition'
1839 | mock_catalog_manager.create_partition.return_value = expected_response
1840 |
1841 | # Create a comprehensive partition input
1842 | partition_input = {
1843 | 'StorageDescriptor': {
1844 | 'Columns': [
1845 | {'Name': 'id', 'Type': 'int'},
1846 | {'Name': 'name', 'Type': 'string'},
1847 | {'Name': 'timestamp', 'Type': 'timestamp'},
1848 | ],
1849 | 'Location': 's3://test-bucket/test-db/test-table/year=2023/month=01/',
1850 | 'InputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat',
1851 | 'OutputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat',
1852 | 'Compressed': True,
1853 | 'SerdeInfo': {
1854 | 'SerializationLibrary': 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe',
1855 | 'Parameters': {'serialization.format': '1'},
1856 | },
1857 | },
1858 | 'Parameters': {
1859 | 'classification': 'parquet',
1860 | 'compressionType': 'snappy',
1861 | 'recordCount': '1000',
1862 | 'averageRecordSize': '100',
1863 | },
1864 | 'LastAccessTime': '2023-01-01T00:00:00Z',
1865 | }
1866 |
1867 | # Call the method with the partition input
1868 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1869 | mock_ctx,
1870 | operation='create-partition',
1871 | database_name='test-db',
1872 | table_name='test-table',
1873 | partition_values=['2023', '01'],
1874 | partition_input=partition_input,
1875 | catalog_id='123456789012',
1876 | )
1877 |
1878 | # Verify that the method was called with the correct parameters
1879 | mock_catalog_manager.create_partition.assert_called_once_with(
1880 | ctx=mock_ctx,
1881 | database_name='test-db',
1882 | table_name='test-table',
1883 | partition_values=['2023', '01'],
1884 | partition_input=partition_input,
1885 | catalog_id='123456789012',
1886 | )
1887 |
1888 | # Verify that the result is the expected response
1889 | assert result == expected_response
1890 | assert result.database_name == 'test-db'
1891 | assert result.table_name == 'test-table'
1892 | assert result.partition_values == ['2023', '01']
1893 |
1894 | @pytest.mark.asyncio
1895 | async def test_manage_aws_glue_data_catalog_partitions_update_with_partition_input(
1896 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
1897 | ):
1898 | """Test updating a partition with a complete partition input."""
1899 | # Setup the mock to return a response
1900 | expected_response = MagicMock()
1901 | expected_response.isError = False
1902 | expected_response.content = []
1903 | expected_response.database_name = 'test-db'
1904 | expected_response.table_name = 'test-table'
1905 | expected_response.partition_values = ['2023', '01']
1906 | expected_response.operation = 'update-partition'
1907 | mock_catalog_manager.update_partition.return_value = expected_response
1908 |
1909 | # Create a comprehensive partition input for update
1910 | partition_input = {
1911 | 'StorageDescriptor': {
1912 | 'Columns': [
1913 | {'Name': 'id', 'Type': 'int'},
1914 | {'Name': 'name', 'Type': 'string'},
1915 | {'Name': 'timestamp', 'Type': 'timestamp'},
1916 | {'Name': 'new_column', 'Type': 'string'}, # Added a new column
1917 | ],
1918 | 'Location': 's3://test-bucket/test-db/test-table/year=2023/month=01/',
1919 | 'InputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat',
1920 | 'OutputFormat': 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat',
1921 | 'Compressed': True,
1922 | 'SerdeInfo': {
1923 | 'SerializationLibrary': 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe',
1924 | 'Parameters': {'serialization.format': '1'},
1925 | },
1926 | },
1927 | 'Parameters': {
1928 | 'classification': 'parquet',
1929 | 'compressionType': 'gzip', # Changed from snappy to gzip
1930 | 'recordCount': '2000', # Updated record count
1931 | 'averageRecordSize': '120', # Updated average record size
1932 | 'updatedAt': '2023-02-01T00:00:00Z', # Added update timestamp
1933 | },
1934 | 'LastAccessTime': '2023-02-01T00:00:00Z', # Updated last access time
1935 | }
1936 |
1937 | # Call the method with the partition input
1938 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
1939 | mock_ctx,
1940 | operation='update-partition',
1941 | database_name='test-db',
1942 | table_name='test-table',
1943 | partition_values=['2023', '01'],
1944 | partition_input=partition_input,
1945 | catalog_id='123456789012',
1946 | )
1947 |
1948 | # Verify that the method was called with the correct parameters
1949 | mock_catalog_manager.update_partition.assert_called_once_with(
1950 | ctx=mock_ctx,
1951 | database_name='test-db',
1952 | table_name='test-table',
1953 | partition_values=['2023', '01'],
1954 | partition_input=partition_input,
1955 | catalog_id='123456789012',
1956 | )
1957 |
1958 | # Verify that the result is the expected response
1959 | assert result == expected_response
1960 | assert result.database_name == 'test-db'
1961 | assert result.table_name == 'test-table'
1962 | assert result.partition_values == ['2023', '01']
1963 |
1964 | @pytest.mark.asyncio
1965 | async def test_manage_aws_glue_data_catalog_tables_search_tables_with_parameters(
1966 | self, handler, mock_ctx, mock_table_manager
1967 | ):
1968 | """Test that search tables operation works correctly with all parameters."""
1969 | # Setup the mock to return a response
1970 | expected_response = MagicMock()
1971 | expected_response.isError = False
1972 | expected_response.content = []
1973 | expected_response.tables = [
1974 | {'DatabaseName': 'test-db', 'Name': 'test-table1', 'Description': 'First test table'},
1975 | {'DatabaseName': 'test-db', 'Name': 'test-table2', 'Description': 'Second test table'},
1976 | ]
1977 | expected_response.search_text = 'test'
1978 | expected_response.count = 2
1979 | expected_response.operation = 'search-tables'
1980 | # expected_response.next_token = 'next-token-value'
1981 | mock_table_manager.search_tables.return_value = expected_response
1982 |
1983 | # Call the method with search-tables operation and all parameters
1984 | result = await handler.manage_aws_glue_data_catalog_tables(
1985 | mock_ctx,
1986 | operation='search-tables',
1987 | database_name='test-db',
1988 | search_text='test',
1989 | max_results=10,
1990 | catalog_id='123456789012',
1991 | )
1992 |
1993 | # Verify that the method was called with the correct parameters
1994 | mock_table_manager.search_tables.assert_called_once_with(
1995 | ctx=mock_ctx,
1996 | search_text='test',
1997 | max_results=10,
1998 | catalog_id='123456789012',
1999 | )
2000 |
2001 | # Verify that the result is the expected response
2002 | assert result == expected_response
2003 | assert len(result.tables) == 2
2004 | assert result.tables[0]['Name'] == 'test-table1'
2005 | assert result.tables[1]['Name'] == 'test-table2'
2006 | assert result.search_text == 'test'
2007 | assert result.count == 2
2008 | # assert result.next_token == 'next-token-value'
2009 |
2010 | @pytest.mark.asyncio
2011 | async def test_manage_aws_glue_data_catalog_partitions_list_partitions_with_parameters(
2012 | self, handler, mock_ctx, mock_catalog_manager
2013 | ):
2014 | """Test that list partitions operation works correctly with all parameters."""
2015 | # Setup the mock to return a response
2016 | expected_response = MagicMock()
2017 | expected_response.isError = False
2018 | expected_response.content = []
2019 | expected_response.partitions = [
2020 | {
2021 | 'Values': ['2023', '01'],
2022 | 'StorageDescriptor': {'Location': 's3://bucket/path/2023/01'},
2023 | },
2024 | {
2025 | 'Values': ['2023', '02'],
2026 | 'StorageDescriptor': {'Location': 's3://bucket/path/2023/02'},
2027 | },
2028 | ]
2029 | expected_response.count = 2
2030 | expected_response.operation = 'list-partitions'
2031 | # expected_response.next_token = 'next-token-value'
2032 | mock_catalog_manager.list_partitions.return_value = expected_response
2033 |
2034 | # Call the method with list-partitions operation and all parameters
2035 | result = await handler.manage_aws_glue_data_catalog_partitions(
2036 | mock_ctx,
2037 | operation='list-partitions',
2038 | database_name='test-db',
2039 | table_name='test-table',
2040 | max_results=10,
2041 | expression="year='2023'",
2042 | catalog_id='123456789012',
2043 | )
2044 |
2045 | # Verify that the method was called with the correct parameters
2046 | mock_catalog_manager.list_partitions.assert_called_once_with(
2047 | ctx=mock_ctx,
2048 | database_name='test-db',
2049 | table_name='test-table',
2050 | max_results=10,
2051 | expression="year='2023'",
2052 | catalog_id='123456789012',
2053 | next_token=ANY,
2054 | )
2055 |
2056 | # Verify that the result is the expected response
2057 | assert result == expected_response
2058 | assert len(result.partitions) == 2
2059 | assert result.partitions[0]['Values'] == ['2023', '01']
2060 | assert result.partitions[1]['Values'] == ['2023', '02']
2061 | assert result.count == 2
2062 | # assert result.next_token == 'next-token-value'
2063 |
2064 | @pytest.mark.asyncio
2065 | async def test_manage_aws_glue_data_catalog_create_with_catalog_input(
2066 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
2067 | ):
2068 | """Test creating a catalog with a complete catalog input."""
2069 | # Setup the mock to return a response
2070 | expected_response = MagicMock()
2071 | expected_response.isError = False
2072 | expected_response.content = []
2073 | expected_response.catalog_id = 'test-catalog'
2074 | expected_response.operation = 'create-catalog'
2075 | mock_catalog_manager.create_catalog.return_value = expected_response
2076 |
2077 | # Create a comprehensive catalog input
2078 | catalog_input = {
2079 | 'Name': 'Test Catalog',
2080 | 'Description': 'Test catalog for unit testing',
2081 | 'Type': 'GLUE',
2082 | 'Parameters': {'key1': 'value1', 'key2': 'value2'},
2083 | 'Tags': {'Environment': 'Test', 'Project': 'UnitTest'},
2084 | }
2085 |
2086 | # Call the method with the catalog input
2087 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
2088 | mock_ctx,
2089 | operation='create-catalog',
2090 | catalog_id='test-catalog',
2091 | catalog_input=catalog_input,
2092 | )
2093 |
2094 | # Verify that the method was called with the correct parameters
2095 | mock_catalog_manager.create_catalog.assert_called_once_with(
2096 | ctx=mock_ctx,
2097 | catalog_name='test-catalog',
2098 | catalog_input=catalog_input,
2099 | )
2100 |
2101 | # Verify that the result is the expected response
2102 | assert result == expected_response
2103 | assert result.catalog_id == 'test-catalog'
2104 |
2105 | @pytest.mark.asyncio
2106 | async def test_manage_aws_glue_data_catalog_get_catalog_with_parameters(
2107 | self, handler, mock_ctx, mock_catalog_manager
2108 | ):
2109 | """Test that get catalog operation works correctly with all parameters."""
2110 | # Setup the mock to return a response
2111 | expected_response = MagicMock()
2112 | expected_response.isError = False
2113 | expected_response.content = []
2114 | expected_response.catalog_id = 'test-catalog'
2115 | expected_response.catalog_definition = {
2116 | 'Name': 'Test Catalog',
2117 | 'Description': 'Test catalog description',
2118 | 'Type': 'GLUE',
2119 | 'Parameters': {'key1': 'value1', 'key2': 'value2'},
2120 | }
2121 | expected_response.name = 'Test Catalog'
2122 | expected_response.description = 'Test catalog description'
2123 | expected_response.create_time = '2023-01-01T00:00:00Z'
2124 | expected_response.update_time = '2023-01-01T00:00:00Z'
2125 | expected_response.operation = 'get-catalog'
2126 | mock_catalog_manager.get_catalog.return_value = expected_response
2127 |
2128 | # Call the method with get-catalog operation
2129 | result = await handler.manage_aws_glue_data_catalog(
2130 | mock_ctx,
2131 | operation='get-catalog',
2132 | catalog_id='test-catalog',
2133 | )
2134 |
2135 | # Verify that the method was called with the correct parameters
2136 | mock_catalog_manager.get_catalog.assert_called_once_with(
2137 | ctx=mock_ctx,
2138 | catalog_id='test-catalog',
2139 | )
2140 |
2141 | # Verify that the result is the expected response
2142 | assert result == expected_response
2143 | assert result.catalog_id == 'test-catalog'
2144 | assert result.name == 'Test Catalog'
2145 | assert result.description == 'Test catalog description'
2146 | assert result.create_time == '2023-01-01T00:00:00Z'
2147 | assert result.update_time == '2023-01-01T00:00:00Z'
2148 |
2149 | @pytest.mark.asyncio
2150 | async def test_manage_aws_glue_data_catalog_tables_invalid_operation_with_write_access(
2151 | self, handler_with_write_access, mock_ctx
2152 | ):
2153 | """Test that an invalid operation returns an error response with write access."""
2154 | # Call the method with an invalid operation
2155 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
2156 | mock_ctx, operation='invalid-operation', database_name='test-db'
2157 | )
2158 |
2159 | # Verify that the result is an error response
2160 | assert result.isError is True
2161 | assert 'Invalid operation' in result.content[0].text
2162 | assert result.database_name == 'test-db'
2163 | assert result.table_name == ''
2164 | assert result.operation == 'get-table'
2165 |
2166 | @pytest.mark.asyncio
2167 | async def test_manage_aws_glue_data_catalog_connections_invalid_operation_with_write_access(
2168 | self, handler_with_write_access, mock_ctx
2169 | ):
2170 | """Test that an invalid operation returns an error response with write access."""
2171 | # Call the method with an invalid operation
2172 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
2173 | mock_ctx, operation='invalid-operation', connection_name='test-connection'
2174 | )
2175 |
2176 | # Verify that the result is an error response
2177 | assert result.isError is True
2178 | assert 'Invalid operation' in result.content[0].text
2179 | assert result.connection_name == ''
2180 | assert result.operation == 'get-connection'
2181 |
2182 | @pytest.mark.asyncio
2183 | async def test_manage_aws_glue_data_catalog_partitions_invalid_operation_with_write_access(
2184 | self, handler_with_write_access, mock_ctx
2185 | ):
2186 | """Test that an invalid operation returns an error response with write access."""
2187 | # Call the method with an invalid operation
2188 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
2189 | mock_ctx,
2190 | operation='invalid-operation',
2191 | database_name='test-db',
2192 | table_name='test-table',
2193 | )
2194 |
2195 | # Verify that the result is an error response
2196 | assert result.isError is True
2197 | assert 'Invalid operation' in result.content[0].text
2198 | assert result.database_name == 'test-db'
2199 | assert result.table_name == 'test-table'
2200 | assert result.partition_values == []
2201 | assert result.operation == 'get-partition'
2202 |
2203 | @pytest.mark.asyncio
2204 | async def test_manage_aws_glue_data_catalog_tables_search_tables_no_parameters(
2205 | self, handler, mock_ctx, mock_table_manager
2206 | ):
2207 | """Test that search tables operation works correctly with minimal parameters."""
2208 | # Setup the mock to return a response
2209 | expected_response = MagicMock()
2210 | expected_response.isError = False
2211 | expected_response.content = []
2212 | expected_response.tables = []
2213 | expected_response.search_text = None
2214 | expected_response.count = 0
2215 | expected_response.operation = 'search-tables'
2216 | mock_table_manager.search_tables.return_value = expected_response
2217 |
2218 | # Call the method with search-tables operation and minimal parameters
2219 | result = await handler.manage_aws_glue_data_catalog_tables(
2220 | mock_ctx,
2221 | operation='search-tables',
2222 | database_name='test-db',
2223 | )
2224 |
2225 | # Verify that the method was called
2226 | assert mock_table_manager.search_tables.call_count == 1
2227 |
2228 | # Verify that the result is the expected response
2229 | assert result == expected_response
2230 |
2231 | @pytest.mark.asyncio
2232 | async def test_manage_aws_glue_data_catalog_partitions_list_partitions_no_parameters(
2233 | self, handler, mock_ctx, mock_catalog_manager
2234 | ):
2235 | """Test that list partitions operation works correctly with minimal parameters."""
2236 | # Setup the mock to return a response
2237 | expected_response = MagicMock()
2238 | expected_response.isError = False
2239 | expected_response.content = []
2240 | expected_response.partitions = []
2241 | expected_response.count = 0
2242 | expected_response.operation = 'list-partitions'
2243 | mock_catalog_manager.list_partitions.return_value = expected_response
2244 |
2245 | # Call the method with list-partitions operation and minimal parameters
2246 | result = await handler.manage_aws_glue_data_catalog_partitions(
2247 | mock_ctx,
2248 | operation='list-partitions',
2249 | database_name='test-db',
2250 | table_name='test-table',
2251 | )
2252 |
2253 | # Verify that the method was called
2254 | assert mock_catalog_manager.list_partitions.call_count == 1
2255 |
2256 | # Verify that the result is the expected response
2257 | assert result == expected_response
2258 |
2259 | @pytest.mark.asyncio
2260 | async def test_manage_aws_glue_data_catalog_missing_catalog_id_for_get(
2261 | self, handler, mock_ctx
2262 | ):
2263 | """Test that missing catalog_id parameter for get-catalog operation returns an error response."""
2264 | # Call the method without catalog_id
2265 | with pytest.raises(ValueError) as e:
2266 | await handler.manage_aws_glue_data_catalog(
2267 | mock_ctx,
2268 | operation='get-catalog',
2269 | )
2270 |
2271 | assert 'catalog_id is required' in str(e.value)
2272 |
2273 | @pytest.mark.asyncio
2274 | async def test_manage_aws_glue_data_catalog_missing_catalog_id_for_delete(
2275 | self, handler_with_write_access, mock_ctx
2276 | ):
2277 | """Test that missing catalog_id parameter for delete-catalog operation returns an error response."""
2278 | # Call the method without catalog_id
2279 | with pytest.raises(ValueError) as e:
2280 | await handler_with_write_access.manage_aws_glue_data_catalog(
2281 | mock_ctx,
2282 | operation='delete-catalog',
2283 | )
2284 |
2285 | assert 'catalog_id is required' in str(e.value)
2286 |
2287 | @pytest.mark.asyncio
2288 | async def test_manage_aws_glue_data_catalog_tables_other_write_access_error(
2289 | self, handler, mock_ctx
2290 | ):
2291 | """Test that other write operations are not allowed without write access."""
2292 | # Call the method with a non-standard write operation
2293 | result = await handler.manage_aws_glue_data_catalog_tables(
2294 | mock_ctx,
2295 | operation='other-write-operation',
2296 | database_name='test-db',
2297 | table_name='test-table',
2298 | )
2299 |
2300 | # Verify that the result is an error response
2301 | assert result.isError is True
2302 | assert 'Invalid operation' in result.content[0].text
2303 | assert result.database_name == 'test-db'
2304 | assert result.table_name == ''
2305 |
2306 | @pytest.mark.asyncio
2307 | async def test_manage_aws_glue_data_catalog_connections_other_write_access_error(
2308 | self, handler, mock_ctx
2309 | ):
2310 | """Test that other write operations are not allowed without write access."""
2311 | # Call the method with a non-standard write operation
2312 | result = await handler.manage_aws_glue_data_catalog_connections(
2313 | mock_ctx,
2314 | operation='other-write-operation',
2315 | connection_name='test-connection',
2316 | )
2317 |
2318 | # Verify that the result is an error response
2319 | assert result.isError is True
2320 | assert 'Invalid operation' in result.content[0].text
2321 | assert result.connection_name == ''
2322 |
2323 | @pytest.mark.asyncio
2324 | async def test_manage_aws_glue_data_catalog_partitions_other_write_access_error(
2325 | self, handler, mock_ctx
2326 | ):
2327 | """Test that other write operations are not allowed without write access."""
2328 | # Call the method with a non-standard write operation
2329 | result = await handler.manage_aws_glue_data_catalog_partitions(
2330 | mock_ctx,
2331 | operation='other-write-operation',
2332 | database_name='test-db',
2333 | table_name='test-table',
2334 | )
2335 |
2336 | # Verify that the result is an error response
2337 | assert result.isError is True
2338 | assert 'Invalid operation: other-write-operation' in result.content[0].text
2339 | assert result.database_name == 'test-db'
2340 | assert result.table_name == 'test-table'
2341 | assert result.partition_values == []
2342 |
2343 | @pytest.mark.asyncio
2344 | async def test_manage_aws_glue_data_catalog_other_write_access_error(self, handler, mock_ctx):
2345 | """Test that other write operations are not allowed without write access."""
2346 | # Call the method with a non-standard write operation
2347 | result = await handler.manage_aws_glue_data_catalog(
2348 | mock_ctx,
2349 | operation='other-write-operation',
2350 | catalog_id='test-catalog',
2351 | )
2352 |
2353 | # Verify that the result is an error response
2354 | assert result.isError is True
2355 | assert 'Invalid operation: other-write-operation' in result.content[0].text
2356 | assert result.catalog_id == ''
2357 |
2358 | @pytest.mark.asyncio
2359 | async def test_manage_aws_glue_data_catalog_tables_create_with_catalog_id(
2360 | self, handler_with_write_access, mock_ctx, mock_table_manager
2361 | ):
2362 | """Test creating a table with a catalog ID."""
2363 | # Setup the mock to return a response
2364 | expected_response = MagicMock()
2365 | expected_response.isError = False
2366 | expected_response.content = []
2367 | expected_response.database_name = 'test-db'
2368 | expected_response.table_name = 'test-table'
2369 | expected_response.operation = 'create-table'
2370 | mock_table_manager.create_table.return_value = expected_response
2371 |
2372 | # Call the method with a catalog ID
2373 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
2374 | mock_ctx,
2375 | operation='create-table',
2376 | database_name='test-db',
2377 | table_name='test-table',
2378 | table_input={'Name': 'test-table'},
2379 | catalog_id='123456789012',
2380 | )
2381 |
2382 | # Verify that the method was called with the correct parameters
2383 | mock_table_manager.create_table.assert_called_once_with(
2384 | ctx=mock_ctx,
2385 | database_name='test-db',
2386 | table_name='test-table',
2387 | table_input={'Name': 'test-table'},
2388 | catalog_id='123456789012',
2389 | )
2390 |
2391 | # Verify that the result is the expected response
2392 | assert result == expected_response
2393 |
2394 | @pytest.mark.asyncio
2395 | async def test_manage_aws_glue_data_catalog_tables_list_tables_with_max_results(
2396 | self, handler, mock_ctx, mock_table_manager
2397 | ):
2398 | """Test listing tables with max_results parameter."""
2399 | # Setup the mock to return a response
2400 | expected_response = MagicMock()
2401 | expected_response.isError = False
2402 | expected_response.content = []
2403 | expected_response.tables = [{'Name': 'test-table1'}, {'Name': 'test-table2'}]
2404 | expected_response.count = 2
2405 | expected_response.operation = 'list-tables'
2406 | mock_table_manager.list_tables.return_value = expected_response
2407 |
2408 | # Call the method with max_results
2409 | result = await handler.manage_aws_glue_data_catalog_tables(
2410 | mock_ctx,
2411 | operation='list-tables',
2412 | database_name='test-db',
2413 | max_results=10,
2414 | )
2415 |
2416 | # Verify that the method was called with the correct parameters
2417 | assert mock_table_manager.list_tables.call_count == 1
2418 | assert mock_table_manager.list_tables.call_args[1]['max_results'] == 10
2419 |
2420 | # Verify that the result is the expected response
2421 | assert result == expected_response
2422 | assert len(result.tables) == 2
2423 |
2424 | @pytest.mark.asyncio
2425 | async def test_manage_aws_glue_data_catalog_connections_get_with_catalog_id(
2426 | self, handler, mock_ctx, mock_catalog_manager
2427 | ):
2428 | """Test getting a connection with a catalog ID."""
2429 | # Setup the mock to return a response
2430 | expected_response = MagicMock()
2431 | expected_response.isError = False
2432 | expected_response.content = []
2433 | expected_response.connection_name = 'test-connection'
2434 | expected_response.operation = 'get-connection'
2435 | expected_response.catalog_id = '123456789012'
2436 | mock_catalog_manager.get_connection.return_value = expected_response
2437 |
2438 | # Call the method with a catalog ID
2439 | result = await handler.manage_aws_glue_data_catalog_connections(
2440 | mock_ctx,
2441 | operation='get-connection',
2442 | connection_name='test-connection',
2443 | catalog_id='123456789012',
2444 | )
2445 |
2446 | # Verify that the method was called with the correct parameters
2447 | assert mock_catalog_manager.get_connection.call_count == 1
2448 | assert mock_catalog_manager.get_connection.call_args[1]['catalog_id'] == '123456789012'
2449 |
2450 | # Verify that the result is the expected response
2451 | assert result == expected_response
2452 | assert result.catalog_id == '123456789012'
2453 |
2454 | @pytest.mark.asyncio
2455 | async def test_manage_aws_glue_data_catalog_partitions_get_with_catalog_id(
2456 | self, handler, mock_ctx, mock_catalog_manager
2457 | ):
2458 | """Test getting a partition with a catalog ID."""
2459 | # Setup the mock to return a response
2460 | expected_response = MagicMock()
2461 | expected_response.isError = False
2462 | expected_response.content = []
2463 | expected_response.database_name = 'test-db'
2464 | expected_response.table_name = 'test-table'
2465 | expected_response.partition_values = ['2023', '01']
2466 | expected_response.operation = 'get-partition'
2467 | mock_catalog_manager.get_partition.return_value = expected_response
2468 |
2469 | # Call the method with a catalog ID
2470 | result = await handler.manage_aws_glue_data_catalog_partitions(
2471 | mock_ctx,
2472 | operation='get-partition',
2473 | database_name='test-db',
2474 | table_name='test-table',
2475 | partition_values=['2023', '01'],
2476 | catalog_id='123456789012',
2477 | )
2478 |
2479 | # Verify that the method was called with the correct parameters
2480 | assert mock_catalog_manager.get_partition.call_count == 1
2481 | assert mock_catalog_manager.get_partition.call_args[1]['catalog_id'] == '123456789012'
2482 |
2483 | # Verify that the result is the expected response
2484 | assert result == expected_response
2485 | assert result.partition_values == ['2023', '01']
2486 |
2487 | @pytest.mark.asyncio
2488 | async def test_manage_aws_glue_data_catalog_tables_exception_handling_specific(
2489 | self, handler_with_write_access, mock_ctx, mock_table_manager
2490 | ):
2491 | """Test specific exception handling in manage_aws_glue_data_catalog_tables."""
2492 | # Setup the mock to raise a specific exception
2493 | mock_table_manager.create_table.side_effect = ValueError('Specific test exception')
2494 |
2495 | # Call the method
2496 | with pytest.raises(ValueError) as excinfo:
2497 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
2498 | mock_ctx,
2499 | operation='create-table',
2500 | database_name='test-db',
2501 | table_name='test-table',
2502 | table_input={'Name': 'test-table'},
2503 | )
2504 |
2505 | # Verify that the correct error message is raised
2506 | assert 'Specific test exception' in str(excinfo.value)
2507 |
2508 | @pytest.mark.asyncio
2509 | async def test_manage_aws_glue_data_catalog_connections_exception_handling_specific(
2510 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
2511 | ):
2512 | """Test specific exception handling in manage_aws_glue_data_catalog_connections."""
2513 | # Setup the mock to raise a specific exception
2514 | mock_catalog_manager.create_connection.side_effect = ValueError('Specific test exception')
2515 |
2516 | # Call the method
2517 | with pytest.raises(ValueError) as excinfo:
2518 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
2519 | mock_ctx,
2520 | operation='create-connection',
2521 | connection_name='test-connection',
2522 | connection_input={'ConnectionType': 'JDBC'},
2523 | )
2524 |
2525 | # Verify that the correct error message is raised
2526 | assert 'Specific test exception' in str(excinfo.value)
2527 |
2528 | @pytest.mark.asyncio
2529 | async def test_manage_aws_glue_data_catalog_partitions_exception_handling_specific(
2530 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
2531 | ):
2532 | """Test specific exception handling in manage_aws_glue_data_catalog_partitions."""
2533 | # Setup the mock to raise a specific exception
2534 | mock_catalog_manager.create_partition.side_effect = ValueError('Specific test exception')
2535 |
2536 | # Call the method
2537 | with pytest.raises(ValueError) as excinfo:
2538 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
2539 | mock_ctx,
2540 | operation='create-partition',
2541 | database_name='test-db',
2542 | table_name='test-table',
2543 | partition_values=['2023', '01'],
2544 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023/01'}},
2545 | )
2546 |
2547 | # Verify that the correct error message is raised
2548 | assert 'Specific test exception' in str(excinfo.value)
2549 |
2550 | @pytest.mark.asyncio
2551 | async def test_manage_aws_glue_data_catalog_exception_handling_specific(
2552 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
2553 | ):
2554 | """Test specific exception handling in manage_aws_glue_data_catalog."""
2555 | # Setup the mock to raise a specific exception
2556 | mock_catalog_manager.create_catalog.side_effect = ValueError('Specific test exception')
2557 |
2558 | # Call the method
2559 | with pytest.raises(ValueError) as excinfo:
2560 | await handler_with_write_access.manage_aws_glue_data_catalog(
2561 | mock_ctx,
2562 | operation='create-catalog',
2563 | catalog_id='test-catalog',
2564 | catalog_input={'Description': 'Test catalog'},
2565 | )
2566 |
2567 | # Verify that the correct error message is raised
2568 | assert 'Specific test exception' in str(excinfo.value)
2569 |
2570 | @pytest.mark.asyncio
2571 | async def test_manage_aws_glue_data_catalog_databases_with_sensitive_data_access(
2572 | self, mock_mcp, mock_ctx, mock_database_manager
2573 | ):
2574 | """Test that the handler works correctly with sensitive data access."""
2575 | # Create a handler with sensitive data access
2576 | with (
2577 | patch(
2578 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogDatabaseManager',
2579 | return_value=mock_database_manager,
2580 | ),
2581 | patch(
2582 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogTableManager',
2583 | return_value=MagicMock(),
2584 | ),
2585 | patch(
2586 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogManager',
2587 | return_value=MagicMock(),
2588 | ),
2589 | ):
2590 | handler = GlueDataCatalogHandler(mock_mcp, allow_sensitive_data_access=True)
2591 | handler.data_catalog_database_manager = mock_database_manager
2592 |
2593 | # Setup the mock to return a response
2594 | expected_response = MagicMock()
2595 | expected_response.isError = False
2596 | expected_response.content = []
2597 | expected_response.database_name = 'test-db'
2598 | expected_response.operation = 'get'
2599 | mock_database_manager.get_database.return_value = expected_response
2600 |
2601 | # Call the method
2602 | result = await handler.manage_aws_glue_data_catalog_databases(
2603 | mock_ctx,
2604 | operation='get-database',
2605 | database_name='test-db',
2606 | )
2607 |
2608 | # Verify that the result is the expected response
2609 | assert result == expected_response
2610 | assert handler.allow_sensitive_data_access is True
2611 |
2612 | @pytest.mark.asyncio
2613 | async def test_manage_aws_glue_data_catalog_databases_with_both_access_flags(
2614 | self, mock_mcp, mock_ctx, mock_database_manager
2615 | ):
2616 | """Test that the handler works correctly with both write and sensitive data access."""
2617 | # Create a handler with both write and sensitive data access
2618 | with (
2619 | patch(
2620 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogDatabaseManager',
2621 | return_value=mock_database_manager,
2622 | ),
2623 | patch(
2624 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogTableManager',
2625 | return_value=MagicMock(),
2626 | ),
2627 | patch(
2628 | 'awslabs.aws_dataprocessing_mcp_server.handlers.glue.data_catalog_handler.DataCatalogManager',
2629 | return_value=MagicMock(),
2630 | ),
2631 | ):
2632 | handler = GlueDataCatalogHandler(
2633 | mock_mcp, allow_write=True, allow_sensitive_data_access=True
2634 | )
2635 | handler.data_catalog_database_manager = mock_database_manager
2636 |
2637 | # Setup the mock to return a response
2638 | expected_response = MagicMock()
2639 | expected_response.isError = False
2640 | expected_response.content = []
2641 | expected_response.database_name = 'test-db'
2642 | expected_response.operation = 'create'
2643 | mock_database_manager.create_database.return_value = expected_response
2644 |
2645 | # Call the method
2646 | result = await handler.manage_aws_glue_data_catalog_databases(
2647 | mock_ctx,
2648 | operation='create-database',
2649 | database_name='test-db',
2650 | )
2651 |
2652 | # Verify that the result is the expected response
2653 | assert result == expected_response
2654 | assert handler.allow_write is True
2655 | assert handler.allow_sensitive_data_access is True
2656 |
2657 | @pytest.mark.asyncio
2658 | async def test_manage_aws_glue_data_catalog_tables_update_no_write_access(
2659 | self, handler, mock_ctx
2660 | ):
2661 | """Test that update table operation is not allowed without write access."""
2662 | # Call the method with a write operation
2663 | result = await handler.manage_aws_glue_data_catalog_tables(
2664 | mock_ctx,
2665 | operation='update-table',
2666 | database_name='test-db',
2667 | table_name='test-table',
2668 | table_input={'Name': 'test-table'},
2669 | )
2670 |
2671 | # Verify that the result is an error response
2672 | assert result.isError is True
2673 | assert 'not allowed without write access' in result.content[0].text
2674 | assert result.database_name == 'test-db'
2675 | assert result.table_name == ''
2676 | assert result.operation == 'update-table'
2677 |
2678 | @pytest.mark.asyncio
2679 | async def test_manage_aws_glue_data_catalog_tables_search_tables_no_write_access(
2680 | self, handler, mock_ctx
2681 | ):
2682 | """Test that search tables operation is allowed without write access."""
2683 | # Mock the search_tables method to return a response
2684 | expected_response = MagicMock()
2685 | expected_response.isError = False
2686 | expected_response.content = []
2687 | expected_response.tables = []
2688 | expected_response.search_text = 'test'
2689 | expected_response.count = 0
2690 | expected_response.operation = 'search-tables'
2691 | handler.data_catalog_table_manager.search_tables.return_value = expected_response
2692 |
2693 | # Call the method with a read operation
2694 | result = await handler.manage_aws_glue_data_catalog_tables(
2695 | mock_ctx,
2696 | operation='search-tables',
2697 | database_name='test-db',
2698 | search_text='test',
2699 | )
2700 |
2701 | # Verify that the result is the expected response
2702 | assert result == expected_response
2703 | assert result.isError is False
2704 | assert handler.data_catalog_table_manager.search_tables.call_count == 1
2705 |
2706 | @pytest.mark.asyncio
2707 | async def test_manage_aws_glue_data_catalog_tables_list_tables_no_write_access(
2708 | self, handler, mock_ctx
2709 | ):
2710 | """Test that list tables operation is allowed without write access."""
2711 | # Mock the list_tables method to return a response
2712 | expected_response = MagicMock()
2713 | expected_response.isError = False
2714 | expected_response.content = []
2715 | expected_response.tables = []
2716 | expected_response.count = 0
2717 | expected_response.operation = 'list-tables'
2718 | handler.data_catalog_table_manager.list_tables.return_value = expected_response
2719 |
2720 | # Call the method with a read operation
2721 | result = await handler.manage_aws_glue_data_catalog_tables(
2722 | mock_ctx,
2723 | operation='list-tables',
2724 | database_name='test-db',
2725 | )
2726 |
2727 | # Verify that the result is the expected response
2728 | assert result == expected_response
2729 | assert result.isError is False
2730 | assert handler.data_catalog_table_manager.list_tables.call_count == 1
2731 |
2732 | @pytest.mark.asyncio
2733 | async def test_manage_aws_glue_data_catalog_connections_list_connections_no_write_access(
2734 | self, handler, mock_ctx
2735 | ):
2736 | """Test that list connections operation is allowed without write access."""
2737 | # Mock the list_connections method to return a response
2738 | expected_response = MagicMock()
2739 | expected_response.isError = False
2740 | expected_response.content = []
2741 | expected_response.connections = []
2742 | expected_response.count = 0
2743 | expected_response.operation = 'list-connections'
2744 | handler.data_catalog_manager.list_connections.return_value = expected_response
2745 |
2746 | # Call the method with a read operation
2747 | result = await handler.manage_aws_glue_data_catalog_connections(
2748 | mock_ctx,
2749 | operation='list-connections',
2750 | )
2751 |
2752 | # Verify that the result is the expected response
2753 | assert result == expected_response
2754 | assert result.isError is False
2755 | assert handler.data_catalog_manager.list_connections.call_count == 1
2756 |
2757 | @pytest.mark.asyncio
2758 | async def test_manage_aws_glue_data_catalog_partitions_get_partition_no_write_access(
2759 | self, handler, mock_ctx
2760 | ):
2761 | """Test that get partition operation is allowed without write access."""
2762 | # Mock the get_partition method to return a response
2763 | expected_response = MagicMock()
2764 | expected_response.isError = False
2765 | expected_response.content = []
2766 | expected_response.database_name = 'test-db'
2767 | expected_response.table_name = 'test-table'
2768 | expected_response.partition_values = ['2023']
2769 | expected_response.operation = 'get-partition'
2770 | handler.data_catalog_manager.get_partition.return_value = expected_response
2771 |
2772 | # Call the method with a read operation
2773 | result = await handler.manage_aws_glue_data_catalog_partitions(
2774 | mock_ctx,
2775 | operation='get-partition',
2776 | database_name='test-db',
2777 | table_name='test-table',
2778 | partition_values=['2023'],
2779 | )
2780 |
2781 | # Verify that the result is the expected response
2782 | assert result == expected_response
2783 | assert result.isError is False
2784 | assert handler.data_catalog_manager.get_partition.call_count == 1
2785 |
2786 | @pytest.mark.asyncio
2787 | async def test_manage_aws_glue_data_catalog_get_catalog_no_write_access(
2788 | self, handler, mock_ctx
2789 | ):
2790 | """Test that get catalog operation is allowed without write access."""
2791 | # Mock the get_catalog method to return a response
2792 | expected_response = MagicMock()
2793 | expected_response.isError = False
2794 | expected_response.content = []
2795 | expected_response.catalog_id = 'test-catalog'
2796 | expected_response.operation = 'get-catalog'
2797 | handler.data_catalog_manager.get_catalog.return_value = expected_response
2798 |
2799 | # Call the method with a read operation
2800 | result = await handler.manage_aws_glue_data_catalog(
2801 | mock_ctx,
2802 | operation='get-catalog',
2803 | catalog_id='test-catalog',
2804 | )
2805 |
2806 | # Verify that the result is the expected response
2807 | assert result == expected_response
2808 | assert result.isError is False
2809 | assert handler.data_catalog_manager.get_catalog.call_count == 1
2810 |
2811 | @pytest.mark.asyncio
2812 | async def test_manage_aws_glue_data_catalog_tables_exception_handling_general(
2813 | self, handler, mock_ctx
2814 | ):
2815 | """Test general exception handling in manage_aws_glue_data_catalog_tables."""
2816 | # Mock the get_table method to raise a general exception
2817 | handler.data_catalog_table_manager.get_table.side_effect = Exception(
2818 | 'General test exception'
2819 | )
2820 |
2821 | # Call the method
2822 | result = await handler.manage_aws_glue_data_catalog_tables(
2823 | mock_ctx,
2824 | operation='get-table',
2825 | database_name='test-db',
2826 | table_name='test-table',
2827 | )
2828 |
2829 | # Verify that the result is an error response
2830 | assert result.isError is True
2831 | assert (
2832 | 'Error in manage_aws_glue_data_catalog_tables: General test exception'
2833 | in result.content[0].text
2834 | )
2835 | assert result.database_name == 'test-db'
2836 | assert result.table_name == ''
2837 | assert result.operation == 'get-table'
2838 |
2839 | @pytest.mark.asyncio
2840 | async def test_manage_aws_glue_data_catalog_connections_exception_handling_general(
2841 | self, handler, mock_ctx
2842 | ):
2843 | """Test general exception handling in manage_aws_glue_data_catalog_connections."""
2844 | # Mock the get_connection method to raise a general exception
2845 | handler.data_catalog_manager.get_connection.side_effect = Exception(
2846 | 'General test exception'
2847 | )
2848 |
2849 | # Call the method
2850 | result = await handler.manage_aws_glue_data_catalog_connections(
2851 | mock_ctx,
2852 | operation='get-connection',
2853 | connection_name='test-connection',
2854 | )
2855 |
2856 | # Verify that the result is an error response
2857 | assert result.isError is True
2858 | assert (
2859 | 'Error in manage_aws_glue_data_catalog_connections: General test exception'
2860 | in result.content[0].text
2861 | )
2862 | assert result.connection_name == ''
2863 | assert result.operation == 'get-connection'
2864 |
2865 | @pytest.mark.asyncio
2866 | async def test_manage_aws_glue_data_catalog_partitions_exception_handling_general(
2867 | self, handler, mock_ctx
2868 | ):
2869 | """Test general exception handling in manage_aws_glue_data_catalog_partitions."""
2870 | # Mock the get_partition method to raise a general exception
2871 | handler.data_catalog_manager.get_partition.side_effect = Exception(
2872 | 'General test exception'
2873 | )
2874 |
2875 | # Call the method
2876 | result = await handler.manage_aws_glue_data_catalog_partitions(
2877 | mock_ctx,
2878 | operation='get-partition',
2879 | database_name='test-db',
2880 | table_name='test-table',
2881 | partition_values=['2023'],
2882 | )
2883 |
2884 | # Verify that the result is an error response
2885 | assert result.isError is True
2886 | assert (
2887 | 'Error in manage_aws_glue_data_catalog_partitions: General test exception'
2888 | in result.content[0].text
2889 | )
2890 | assert result.database_name == 'test-db'
2891 | assert result.table_name == 'test-table'
2892 | assert result.partition_values == []
2893 | assert result.operation == 'get-partition'
2894 |
2895 | @pytest.mark.asyncio
2896 | async def test_manage_aws_glue_data_catalog_exception_handling_general(
2897 | self, handler, mock_ctx
2898 | ):
2899 | """Test general exception handling in manage_aws_glue_data_catalog."""
2900 | # Mock the get_catalog method to raise a general exception
2901 | handler.data_catalog_manager.get_catalog.side_effect = Exception('General test exception')
2902 |
2903 | # Call the method
2904 | result = await handler.manage_aws_glue_data_catalog(
2905 | mock_ctx,
2906 | operation='get-catalog',
2907 | catalog_id='test-catalog',
2908 | )
2909 |
2910 | # Verify that the result is an error response
2911 | assert result.isError is True
2912 | assert (
2913 | 'Error in manage_aws_glue_data_catalog: General test exception'
2914 | in result.content[0].text
2915 | )
2916 | assert result.catalog_id == 'test-catalog'
2917 | assert result.operation == 'get-catalog'
2918 |
2919 | @pytest.mark.asyncio
2920 | async def test_manage_aws_glue_data_catalog_databases_error_response_for_other_operations(
2921 | self, handler, mock_ctx
2922 | ):
2923 | """Test that an error response is returned for operations not explicitly handled."""
2924 | # Set write access to true to bypass the "not allowed without write access" check
2925 | handler.allow_write = True
2926 |
2927 | # Call the method with an operation that doesn't match any of the explicit cases
2928 | result = await handler.manage_aws_glue_data_catalog_databases(
2929 | mock_ctx,
2930 | operation='unknown-operation',
2931 | database_name='test-db',
2932 | )
2933 |
2934 | # Verify that the result is an error response
2935 | assert result.isError is True
2936 | assert 'Invalid operation' in result.content[0].text
2937 | assert result.database_name == ''
2938 | assert result.description == ''
2939 | assert result.location_uri == ''
2940 | assert result.parameters == {}
2941 | assert result.creation_time == ''
2942 | assert result.operation == 'get-database'
2943 | assert result.catalog_id == ''
2944 |
2945 | @pytest.mark.asyncio
2946 | async def test_manage_aws_glue_data_catalog_databases_with_none_parameters(
2947 | self, handler_with_write_access, mock_ctx, mock_database_manager
2948 | ):
2949 | """Test that the handler works correctly with None parameters."""
2950 | # Setup the mock to return a response
2951 | expected_response = MagicMock()
2952 | expected_response.isError = False
2953 | expected_response.content = []
2954 | expected_response.database_name = 'test-db'
2955 | expected_response.operation = 'create'
2956 | mock_database_manager.create_database.return_value = expected_response
2957 |
2958 | # Call the method with None parameters
2959 | result = await handler_with_write_access.manage_aws_glue_data_catalog_databases(
2960 | mock_ctx,
2961 | operation='create-database',
2962 | database_name='test-db',
2963 | description=None,
2964 | location_uri=None,
2965 | parameters=None,
2966 | catalog_id=None,
2967 | )
2968 |
2969 | # Verify that the method was called with the correct parameters
2970 | mock_database_manager.create_database.assert_called_once_with(
2971 | ctx=mock_ctx,
2972 | database_name='test-db',
2973 | description=None,
2974 | location_uri=None,
2975 | parameters=None,
2976 | catalog_id=None,
2977 | )
2978 |
2979 | # Verify that the result is the expected response
2980 | assert result == expected_response
2981 |
2982 | @pytest.mark.asyncio
2983 | async def test_manage_aws_glue_data_catalog_tables_with_none_parameters(
2984 | self, handler_with_write_access, mock_ctx, mock_table_manager
2985 | ):
2986 | """Test that the handler works correctly with None parameters."""
2987 | # Setup the mock to return a response
2988 | expected_response = MagicMock()
2989 | expected_response.isError = False
2990 | expected_response.content = []
2991 | expected_response.database_name = 'test-db'
2992 | expected_response.table_name = 'test-table'
2993 | expected_response.operation = 'create-table'
2994 | mock_table_manager.create_table.return_value = expected_response
2995 |
2996 | # Call the method with None parameters
2997 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
2998 | mock_ctx,
2999 | operation='create-table',
3000 | database_name='test-db',
3001 | table_name='test-table',
3002 | table_input={'Name': 'test-table'},
3003 | catalog_id=None,
3004 | )
3005 |
3006 | # Verify that the method was called with the correct parameters
3007 | mock_table_manager.create_table.assert_called_once_with(
3008 | ctx=mock_ctx,
3009 | database_name='test-db',
3010 | table_name='test-table',
3011 | table_input={'Name': 'test-table'},
3012 | catalog_id=None,
3013 | )
3014 |
3015 | # Verify that the result is the expected response
3016 | assert result == expected_response
3017 |
3018 | @pytest.mark.asyncio
3019 | async def test_manage_aws_glue_data_catalog_connections_with_none_parameters(
3020 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3021 | ):
3022 | """Test that the handler works correctly with None parameters."""
3023 | # Setup the mock to return a response
3024 | expected_response = MagicMock()
3025 | expected_response.isError = False
3026 | expected_response.content = []
3027 | expected_response.connection_name = 'test-connection'
3028 | expected_response.operation = 'create-connection'
3029 | mock_catalog_manager.create_connection.return_value = expected_response
3030 |
3031 | # Call the method with None parameters
3032 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3033 | mock_ctx,
3034 | operation='create-connection',
3035 | connection_name='test-connection',
3036 | connection_input={'ConnectionType': 'JDBC'},
3037 | catalog_id=None,
3038 | )
3039 |
3040 | # Verify that the method was called with the correct parameters
3041 | mock_catalog_manager.create_connection.assert_called_once_with(
3042 | ctx=mock_ctx,
3043 | connection_name='test-connection',
3044 | connection_input={'ConnectionType': 'JDBC'},
3045 | catalog_id=None,
3046 | )
3047 |
3048 | # Verify that the result is the expected response
3049 | assert result == expected_response
3050 |
3051 | @pytest.mark.asyncio
3052 | async def test_manage_aws_glue_data_catalog_partitions_with_none_parameters(
3053 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3054 | ):
3055 | """Test that the handler works correctly with None parameters."""
3056 | # Setup the mock to return a response
3057 | expected_response = MagicMock()
3058 | expected_response.isError = False
3059 | expected_response.content = []
3060 | expected_response.database_name = 'test-db'
3061 | expected_response.table_name = 'test-table'
3062 | expected_response.partition_values = ['2023']
3063 | expected_response.operation = 'create-partition'
3064 | mock_catalog_manager.create_partition.return_value = expected_response
3065 |
3066 | # Call the method with None parameters
3067 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3068 | mock_ctx,
3069 | operation='create-partition',
3070 | database_name='test-db',
3071 | table_name='test-table',
3072 | partition_values=['2023'],
3073 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023'}},
3074 | catalog_id=None,
3075 | max_results=None,
3076 | expression=None,
3077 | )
3078 |
3079 | # Verify that the method was called with the correct parameters
3080 | mock_catalog_manager.create_partition.assert_called_once_with(
3081 | ctx=mock_ctx,
3082 | database_name='test-db',
3083 | table_name='test-table',
3084 | partition_values=['2023'],
3085 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023'}},
3086 | catalog_id=None,
3087 | )
3088 |
3089 | # Verify that the result is the expected response
3090 | assert result == expected_response
3091 |
3092 | @pytest.mark.asyncio
3093 | async def test_manage_aws_glue_data_catalog_with_none_parameters(
3094 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3095 | ):
3096 | """Test that the handler works correctly with None parameters."""
3097 | # Setup the mock to return a response
3098 | expected_response = MagicMock()
3099 | expected_response.isError = False
3100 | expected_response.content = []
3101 | expected_response.catalog_id = 'test-catalog'
3102 | expected_response.operation = 'create-catalog'
3103 | mock_catalog_manager.create_catalog.return_value = expected_response
3104 |
3105 | # Call the method with None parameters
3106 | result = await handler_with_write_access.manage_aws_glue_data_catalog(
3107 | mock_ctx,
3108 | operation='create-catalog',
3109 | catalog_id='test-catalog',
3110 | catalog_input={'Description': 'Test catalog'},
3111 | )
3112 |
3113 | # Verify that the method was called with the correct parameters
3114 | mock_catalog_manager.create_catalog.assert_called_once_with(
3115 | ctx=mock_ctx,
3116 | catalog_name='test-catalog',
3117 | catalog_input={'Description': 'Test catalog'},
3118 | )
3119 |
3120 | # Verify that the result is the expected response
3121 | assert result == expected_response
3122 |
3123 | @pytest.mark.asyncio
3124 | async def test_manage_aws_glue_data_catalog_tables_update_with_catalog_id(
3125 | self, handler_with_write_access, mock_ctx, mock_table_manager
3126 | ):
3127 | """Test updating a table with a catalog ID."""
3128 | # Setup the mock to return a response
3129 | expected_response = MagicMock()
3130 | expected_response.isError = False
3131 | expected_response.content = []
3132 | expected_response.database_name = 'test-db'
3133 | expected_response.table_name = 'test-table'
3134 | expected_response.operation = 'update-table'
3135 | mock_table_manager.update_table.return_value = expected_response
3136 |
3137 | # Call the method with a catalog ID
3138 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3139 | mock_ctx,
3140 | operation='update-table',
3141 | database_name='test-db',
3142 | table_name='test-table',
3143 | table_input={'Name': 'test-table'},
3144 | catalog_id='123456789012',
3145 | )
3146 |
3147 | # Verify that the method was called with the correct parameters
3148 | mock_table_manager.update_table.assert_called_once_with(
3149 | ctx=mock_ctx,
3150 | database_name='test-db',
3151 | table_name='test-table',
3152 | table_input={'Name': 'test-table'},
3153 | catalog_id='123456789012',
3154 | )
3155 |
3156 | # Verify that the result is the expected response
3157 | assert result == expected_response
3158 |
3159 | @pytest.mark.asyncio
3160 | async def test_manage_aws_glue_data_catalog_connections_update_with_catalog_id(
3161 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3162 | ):
3163 | """Test updating a connection with a catalog ID."""
3164 | # Setup the mock to return a response
3165 | expected_response = MagicMock()
3166 | expected_response.isError = False
3167 | expected_response.content = []
3168 | expected_response.connection_name = 'test-connection'
3169 | expected_response.operation = 'update-connection'
3170 | expected_response.catalog_id = '123456789012'
3171 | mock_catalog_manager.update_connection.return_value = expected_response
3172 |
3173 | # Call the method with a catalog ID
3174 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3175 | mock_ctx,
3176 | operation='update-connection',
3177 | connection_name='test-connection',
3178 | connection_input={'ConnectionType': 'JDBC'},
3179 | catalog_id='123456789012',
3180 | )
3181 |
3182 | # Verify that the method was called with the correct parameters
3183 | mock_catalog_manager.update_connection.assert_called_once_with(
3184 | ctx=mock_ctx,
3185 | connection_name='test-connection',
3186 | connection_input={'ConnectionType': 'JDBC'},
3187 | catalog_id='123456789012',
3188 | )
3189 |
3190 | # Verify that the result is the expected response
3191 | assert result == expected_response
3192 | assert result.catalog_id == '123456789012'
3193 |
3194 | @pytest.mark.asyncio
3195 | async def test_manage_aws_glue_data_catalog_partitions_update_with_catalog_id(
3196 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3197 | ):
3198 | """Test updating a partition with a catalog ID."""
3199 | # Setup the mock to return a response
3200 | expected_response = MagicMock()
3201 | expected_response.isError = False
3202 | expected_response.content = []
3203 | expected_response.database_name = 'test-db'
3204 | expected_response.table_name = 'test-table'
3205 | expected_response.partition_values = ['2023']
3206 | expected_response.operation = 'update-partition'
3207 | mock_catalog_manager.update_partition.return_value = expected_response
3208 |
3209 | # Call the method with a catalog ID
3210 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3211 | mock_ctx,
3212 | operation='update-partition',
3213 | database_name='test-db',
3214 | table_name='test-table',
3215 | partition_values=['2023'],
3216 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023'}},
3217 | catalog_id='123456789012',
3218 | )
3219 |
3220 | # Verify that the method was called with the correct parameters
3221 | mock_catalog_manager.update_partition.assert_called_once_with(
3222 | ctx=mock_ctx,
3223 | database_name='test-db',
3224 | table_name='test-table',
3225 | partition_values=['2023'],
3226 | partition_input={'StorageDescriptor': {'Location': 's3://bucket/path/2023'}},
3227 | catalog_id='123456789012',
3228 | )
3229 |
3230 | # Verify that the result is the expected response
3231 | assert result == expected_response
3232 |
3233 | @pytest.mark.asyncio
3234 | async def test_manage_aws_glue_data_catalog_tables_delete_with_catalog_id(
3235 | self, handler_with_write_access, mock_ctx, mock_table_manager
3236 | ):
3237 | """Test deleting a table with a catalog ID."""
3238 | # Setup the mock to return a response
3239 | expected_response = MagicMock()
3240 | expected_response.isError = False
3241 | expected_response.content = []
3242 | expected_response.database_name = 'test-db'
3243 | expected_response.table_name = 'test-table'
3244 | expected_response.operation = 'delete-table'
3245 | mock_table_manager.delete_table.return_value = expected_response
3246 |
3247 | # Call the method with a catalog ID
3248 | result = await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3249 | mock_ctx,
3250 | operation='delete-table',
3251 | database_name='test-db',
3252 | table_name='test-table',
3253 | catalog_id='123456789012',
3254 | )
3255 |
3256 | # Verify that the method was called with the correct parameters
3257 | mock_table_manager.delete_table.assert_called_once_with(
3258 | ctx=mock_ctx,
3259 | database_name='test-db',
3260 | table_name='test-table',
3261 | catalog_id='123456789012',
3262 | )
3263 |
3264 | # Verify that the result is the expected response
3265 | assert result == expected_response
3266 |
3267 | @pytest.mark.asyncio
3268 | async def test_manage_aws_glue_data_catalog_connections_delete_with_catalog_id(
3269 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3270 | ):
3271 | """Test deleting a connection with a catalog ID."""
3272 | # Setup the mock to return a response
3273 | expected_response = MagicMock()
3274 | expected_response.isError = False
3275 | expected_response.content = []
3276 | expected_response.connection_name = 'test-connection'
3277 | expected_response.operation = 'delete-connection'
3278 | expected_response.catalog_id = '123456789012'
3279 | mock_catalog_manager.delete_connection.return_value = expected_response
3280 |
3281 | # Call the method with a catalog ID
3282 | result = await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3283 | mock_ctx,
3284 | operation='delete-connection',
3285 | connection_name='test-connection',
3286 | catalog_id='123456789012',
3287 | )
3288 |
3289 | # Verify that the method was called with the correct parameters
3290 | mock_catalog_manager.delete_connection.assert_called_once_with(
3291 | ctx=mock_ctx,
3292 | connection_name='test-connection',
3293 | catalog_id='123456789012',
3294 | )
3295 |
3296 | # Verify that the result is the expected response
3297 | assert result == expected_response
3298 | assert result.catalog_id == '123456789012'
3299 |
3300 | @pytest.mark.asyncio
3301 | async def test_manage_aws_glue_data_catalog_partitions_delete_with_catalog_id(
3302 | self, handler_with_write_access, mock_ctx, mock_catalog_manager
3303 | ):
3304 | """Test deleting a partition with a catalog ID."""
3305 | # Setup the mock to return a response
3306 | expected_response = MagicMock()
3307 | expected_response.isError = False
3308 | expected_response.content = []
3309 | expected_response.database_name = 'test-db'
3310 | expected_response.table_name = 'test-table'
3311 | expected_response.partition_values = ['2023']
3312 | expected_response.operation = 'delete-partition'
3313 | mock_catalog_manager.delete_partition.return_value = expected_response
3314 |
3315 | # Call the method with a catalog ID
3316 | result = await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3317 | mock_ctx,
3318 | operation='delete-partition',
3319 | database_name='test-db',
3320 | table_name='test-table',
3321 | partition_values=['2023'],
3322 | catalog_id='123456789012',
3323 | )
3324 |
3325 | # Verify that the method was called with the correct parameters
3326 | mock_catalog_manager.delete_partition.assert_called_once_with(
3327 | ctx=mock_ctx,
3328 | database_name='test-db',
3329 | table_name='test-table',
3330 | partition_values=['2023'],
3331 | catalog_id='123456789012',
3332 | )
3333 |
3334 | # Verify that the result is the expected response
3335 | assert result == expected_response
3336 |
3337 | # Additional tests to increase coverage for specific lines
3338 |
3339 | @pytest.mark.asyncio
3340 | async def test_manage_aws_glue_data_catalog_tables_with_max_results(
3341 | self, handler, mock_ctx, mock_table_manager
3342 | ):
3343 | """Test listing tables with max_results parameter."""
3344 | # Setup the mock to return a response
3345 | expected_response = MagicMock()
3346 | expected_response.isError = False
3347 | expected_response.content = []
3348 | expected_response.tables = [{'Name': 'test-table1'}, {'Name': 'test-table2'}]
3349 | expected_response.count = 2
3350 | expected_response.operation = 'list-tables'
3351 | mock_table_manager.list_tables.return_value = expected_response
3352 |
3353 | # Call the method with max_results
3354 | result = await handler.manage_aws_glue_data_catalog_tables(
3355 | mock_ctx,
3356 | operation='list-tables',
3357 | database_name='test-db',
3358 | max_results=10,
3359 | )
3360 |
3361 | # Verify that the method was called with the correct parameters
3362 | assert mock_table_manager.list_tables.call_count == 1
3363 | assert mock_table_manager.list_tables.call_args[1]['max_results'] == 10
3364 |
3365 | # Verify that the result is the expected response
3366 | assert result == expected_response
3367 | assert len(result.tables) == 2
3368 |
3369 | @pytest.mark.asyncio
3370 | async def test_manage_aws_glue_data_catalog_databases_create_missing_required_params(
3371 | self, handler_with_write_access, mock_ctx
3372 | ):
3373 | """Test that create database operation with missing required parameters raises a ValueError."""
3374 | # Mock the ValueError that should be raised
3375 | with patch.object(
3376 | handler_with_write_access.data_catalog_database_manager,
3377 | 'create_database',
3378 | side_effect=ValueError('database_name is required for create-database operation'),
3379 | ):
3380 | # Call the method without database_name
3381 | with pytest.raises(ValueError) as excinfo:
3382 | await handler_with_write_access.manage_aws_glue_data_catalog_databases(
3383 | mock_ctx, operation='create-database'
3384 | )
3385 |
3386 | # Verify that the correct error message is raised
3387 | assert 'database_name is required' in str(excinfo.value)
3388 |
3389 | @pytest.mark.asyncio
3390 | async def test_manage_aws_glue_data_catalog_tables_create_missing_required_params(
3391 | self, handler_with_write_access, mock_ctx
3392 | ):
3393 | """Test that create table operation with missing required parameters raises a ValueError."""
3394 | # Call the method without table_name
3395 | with pytest.raises(ValueError) as excinfo:
3396 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3397 | mock_ctx, operation='create-table', database_name='test-db', table_name=None
3398 | )
3399 |
3400 | # Verify that the correct error message is raised
3401 | assert 'database_name, table_input and table_name are required' in str(excinfo.value)
3402 |
3403 | # Call the method without table_input
3404 | with pytest.raises(ValueError) as excinfo:
3405 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3406 | mock_ctx,
3407 | operation='create-table',
3408 | database_name='test-db',
3409 | table_name='test-table',
3410 | table_input=None,
3411 | )
3412 |
3413 | # Verify that the correct error message is raised
3414 | assert 'database_name, table_input and table_name are required' in str(excinfo.value)
3415 |
3416 | @pytest.mark.asyncio
3417 | async def test_manage_aws_glue_data_catalog_tables_delete_missing_required_params(
3418 | self, handler_with_write_access, mock_ctx
3419 | ):
3420 | """Test that delete table operation with missing required parameters raises a ValueError."""
3421 | # Call the method without table_name
3422 | with pytest.raises(ValueError) as excinfo:
3423 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3424 | mock_ctx, operation='delete-table', database_name='test-db', table_name=None
3425 | )
3426 |
3427 | # Verify that the correct error message is raised
3428 | assert 'table_name and database_name required' in str(excinfo.value)
3429 |
3430 | @pytest.mark.asyncio
3431 | async def test_manage_aws_glue_data_catalog_tables_get_missing_required_params(
3432 | self, handler_with_write_access, mock_ctx
3433 | ):
3434 | """Test that get table operation with missing required parameters raises a ValueError."""
3435 | # Call the method without table_name
3436 | with pytest.raises(ValueError) as excinfo:
3437 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3438 | mock_ctx, operation='get-table', database_name='test-db', table_name=None
3439 | )
3440 |
3441 | # Verify that the correct error message is raised
3442 | assert 'table_name is required' in str(excinfo.value)
3443 |
3444 | @pytest.mark.asyncio
3445 | async def test_manage_aws_glue_data_catalog_tables_update_missing_required_params(
3446 | self, handler_with_write_access, mock_ctx
3447 | ):
3448 | """Test that update table operation with missing required parameters raises a ValueError."""
3449 | # Call the method without table_name
3450 | with pytest.raises(ValueError) as excinfo:
3451 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3452 | mock_ctx, operation='update-table', database_name='test-db', table_name=None
3453 | )
3454 |
3455 | # Verify that the correct error message is raised
3456 | assert 'table_name and table_input are required' in str(excinfo.value)
3457 |
3458 | # Call the method without table_input
3459 | with pytest.raises(ValueError) as excinfo:
3460 | await handler_with_write_access.manage_aws_glue_data_catalog_tables(
3461 | mock_ctx,
3462 | operation='update-table',
3463 | database_name='test-db',
3464 | table_name='test-table',
3465 | table_input=None,
3466 | )
3467 |
3468 | # Verify that the correct error message is raised
3469 | assert 'table_name and table_input are required' in str(excinfo.value)
3470 |
3471 | @pytest.mark.asyncio
3472 | async def test_manage_aws_glue_data_catalog_connections_create_missing_required_params(
3473 | self, handler_with_write_access, mock_ctx
3474 | ):
3475 | """Test that create connection operation with missing required parameters raises a ValueError."""
3476 | # Call the method without connection_name
3477 | with pytest.raises(ValueError) as excinfo:
3478 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3479 | mock_ctx, operation='create-connection', connection_name=None
3480 | )
3481 |
3482 | # Verify that the correct error message is raised
3483 | assert 'connection_name and connection_input are required' in str(excinfo.value)
3484 |
3485 | # Call the method without connection_input
3486 | with pytest.raises(ValueError) as excinfo:
3487 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3488 | mock_ctx,
3489 | operation='create-connection',
3490 | connection_name='test-connection',
3491 | connection_input=None,
3492 | )
3493 |
3494 | # Verify that the correct error message is raised
3495 | assert 'connection_name and connection_input are required' in str(excinfo.value)
3496 |
3497 | @pytest.mark.asyncio
3498 | async def test_manage_aws_glue_data_catalog_connections_delete_missing_required_params(
3499 | self, handler_with_write_access, mock_ctx
3500 | ):
3501 | """Test that delete connection operation with missing required parameters raises a ValueError."""
3502 | # Call the method without connection_name
3503 | with pytest.raises(ValueError) as excinfo:
3504 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3505 | mock_ctx, operation='delete-connection', connection_name=None
3506 | )
3507 |
3508 | # Verify that the correct error message is raised
3509 | assert 'connection_name is required' in str(excinfo.value)
3510 |
3511 | @pytest.mark.asyncio
3512 | async def test_manage_aws_glue_data_catalog_connections_get_missing_required_params(
3513 | self, handler_with_write_access, mock_ctx
3514 | ):
3515 | """Test that get connection operation with missing required parameters raises a ValueError."""
3516 | # Call the method without connection_name
3517 | with pytest.raises(ValueError) as excinfo:
3518 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3519 | mock_ctx, operation='get-connection', connection_name=None
3520 | )
3521 |
3522 | # Verify that the correct error message is raised
3523 | assert 'connection_name is required' in str(excinfo.value)
3524 |
3525 | @pytest.mark.asyncio
3526 | async def test_manage_aws_glue_data_catalog_connections_update_missing_required_params(
3527 | self, handler_with_write_access, mock_ctx
3528 | ):
3529 | """Test that update connection operation with missing required parameters raises a ValueError."""
3530 | # Call the method without connection_name
3531 | with pytest.raises(ValueError) as excinfo:
3532 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3533 | mock_ctx, operation='update-connection', connection_name=None
3534 | )
3535 |
3536 | # Verify that the correct error message is raised
3537 | assert 'connection_name and connection_input are required' in str(excinfo.value)
3538 |
3539 | # Call the method without connection_input
3540 | with pytest.raises(ValueError) as excinfo:
3541 | await handler_with_write_access.manage_aws_glue_data_catalog_connections(
3542 | mock_ctx,
3543 | operation='update-connection',
3544 | connection_name='test-connection',
3545 | connection_input=None,
3546 | )
3547 |
3548 | # Verify that the correct error message is raised
3549 | assert 'connection_name and connection_input are required' in str(excinfo.value)
3550 |
3551 | @pytest.mark.asyncio
3552 | async def test_manage_aws_glue_data_catalog_partitions_create_missing_required_params(
3553 | self, handler_with_write_access, mock_ctx
3554 | ):
3555 | """Test that create partition operation with missing required parameters raises a ValueError."""
3556 | # Call the method without partition_values
3557 | with pytest.raises(ValueError) as excinfo:
3558 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3559 | mock_ctx,
3560 | operation='create-partition',
3561 | database_name='test-db',
3562 | table_name='test-table',
3563 | partition_values=None,
3564 | )
3565 |
3566 | # Verify that the correct error message is raised
3567 | assert 'partition_values and partition_input are required' in str(excinfo.value)
3568 |
3569 | # Call the method without partition_input
3570 | with pytest.raises(ValueError) as excinfo:
3571 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3572 | mock_ctx,
3573 | operation='create-partition',
3574 | database_name='test-db',
3575 | table_name='test-table',
3576 | partition_values=['2023'],
3577 | partition_input=None,
3578 | )
3579 |
3580 | # Verify that the correct error message is raised
3581 | assert 'partition_values and partition_input are required' in str(excinfo.value)
3582 |
3583 | @pytest.mark.asyncio
3584 | async def test_manage_aws_glue_data_catalog_partitions_delete_missing_required_params(
3585 | self, handler_with_write_access, mock_ctx
3586 | ):
3587 | """Test that delete partition operation with missing required parameters raises a ValueError."""
3588 | # Call the method without partition_values
3589 | with pytest.raises(ValueError) as excinfo:
3590 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3591 | mock_ctx,
3592 | operation='delete-partition',
3593 | database_name='test-db',
3594 | table_name='test-table',
3595 | partition_values=None,
3596 | )
3597 |
3598 | # Verify that the correct error message is raised
3599 | assert 'partition_values is required' in str(excinfo.value)
3600 |
3601 | @pytest.mark.asyncio
3602 | async def test_manage_aws_glue_data_catalog_partitions_get_missing_required_params(
3603 | self, handler_with_write_access, mock_ctx
3604 | ):
3605 | """Test that get partition operation with missing required parameters raises a ValueError."""
3606 | # Call the method without partition_values
3607 | with pytest.raises(ValueError) as excinfo:
3608 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3609 | mock_ctx,
3610 | operation='get-partition',
3611 | database_name='test-db',
3612 | table_name='test-table',
3613 | partition_values=None,
3614 | )
3615 |
3616 | # Verify that the correct error message is raised
3617 | assert 'partition_values is required' in str(excinfo.value)
3618 |
3619 | @pytest.mark.asyncio
3620 | async def test_manage_aws_glue_data_catalog_partitions_update_missing_required_params(
3621 | self, handler_with_write_access, mock_ctx
3622 | ):
3623 | """Test that update partition operation with missing required parameters raises a ValueError."""
3624 | # Call the method without partition_values
3625 | with pytest.raises(ValueError) as excinfo:
3626 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3627 | mock_ctx,
3628 | operation='update-partition',
3629 | database_name='test-db',
3630 | table_name='test-table',
3631 | partition_values=None,
3632 | )
3633 |
3634 | # Verify that the correct error message is raised
3635 | assert 'partition_values and partition_input are required' in str(excinfo.value)
3636 |
3637 | # Call the method without partition_input
3638 | with pytest.raises(ValueError) as excinfo:
3639 | await handler_with_write_access.manage_aws_glue_data_catalog_partitions(
3640 | mock_ctx,
3641 | operation='update-partition',
3642 | database_name='test-db',
3643 | table_name='test-table',
3644 | partition_values=['2023'],
3645 | partition_input=None,
3646 | )
3647 |
3648 | # Verify that the correct error message is raised
3649 | assert 'partition_values and partition_input are required' in str(excinfo.value)
3650 |
3651 | @pytest.mark.asyncio
3652 | async def test_manage_aws_glue_data_catalog_create_missing_required_params(
3653 | self, handler_with_write_access, mock_ctx
3654 | ):
3655 | """Test that create catalog operation with missing required parameters raises a ValueError."""
3656 | # Call the method without catalog_id
3657 | with pytest.raises(ValueError) as excinfo:
3658 | await handler_with_write_access.manage_aws_glue_data_catalog(
3659 | mock_ctx, operation='create-catalog', catalog_id=None
3660 | )
3661 |
3662 | # Verify that the correct error message is raised
3663 | assert 'catalog_id and catalog_input are required' in str(excinfo.value)
3664 |
3665 | # Call the method without catalog_input
3666 | with pytest.raises(ValueError) as excinfo:
3667 | await handler_with_write_access.manage_aws_glue_data_catalog(
3668 | mock_ctx, operation='create-catalog', catalog_id='test-catalog', catalog_input=None
3669 | )
3670 |
3671 | # Verify that the correct error message is raised
3672 | assert 'catalog_id and catalog_input are required' in str(excinfo.value)
3673 |
3674 | @pytest.mark.asyncio
3675 | async def test_manage_aws_glue_data_catalog_delete_missing_required_params(
3676 | self, handler_with_write_access, mock_ctx
3677 | ):
3678 | """Test that delete catalog operation with missing required parameters raises a ValueError."""
3679 | # Call the method without catalog_id
3680 | with pytest.raises(ValueError) as excinfo:
3681 | await handler_with_write_access.manage_aws_glue_data_catalog(
3682 | mock_ctx, operation='delete-catalog', catalog_id=None
3683 | )
3684 |
3685 | # Verify that the correct error message is raised
3686 | assert 'catalog_id is required' in str(excinfo.value)
3687 |
3688 | @pytest.mark.asyncio
3689 | async def test_manage_aws_glue_data_catalog_get_missing_required_params(
3690 | self, handler_with_write_access, mock_ctx
3691 | ):
3692 | """Test that get catalog operation with missing required parameters raises a ValueError."""
3693 | # Call the method without catalog_id
3694 | with pytest.raises(ValueError) as excinfo:
3695 | await handler_with_write_access.manage_aws_glue_data_catalog(
3696 | mock_ctx, operation='get-catalog', catalog_id=None
3697 | )
3698 |
3699 | # Verify that the correct error message is raised
3700 | assert 'catalog_id is required' in str(excinfo.value)
3701 |
3702 | @pytest.mark.asyncio
3703 | async def test_manage_aws_glue_data_catalog_import_missing_required_params(
3704 | self, handler_with_write_access, mock_ctx
3705 | ):
3706 | """Test that import catalog operation with missing required parameters raises a ValueError."""
3707 | # Call the method without catalog_id
3708 | with pytest.raises(ValueError) as excinfo:
3709 | await handler_with_write_access.manage_aws_glue_data_catalog(
3710 | mock_ctx, operation='import-catalog-to-glue', catalog_id=None
3711 | )
3712 |
3713 | # Verify that the correct error message is raised
3714 | assert 'catalog_id is required' in str(excinfo.value)
3715 |
3716 | @pytest.mark.asyncio
3717 | async def test_manage_aws_glue_data_catalog_partitions_list_with_all_parameters(
3718 | self, handler, mock_ctx, mock_catalog_manager
3719 | ):
3720 | """Test listing partitions with all parameters including next_token."""
3721 | # Setup the mock to return a response
3722 | expected_response = MagicMock()
3723 | expected_response.isError = False
3724 | expected_response.content = []
3725 | expected_response.partitions = [{'Values': ['2023', '01']}, {'Values': ['2023', '02']}]
3726 | expected_response.count = 2
3727 | expected_response.next_token = 'next-token-value'
3728 | expected_response.operation = 'list-partitions'
3729 | mock_catalog_manager.list_partitions.return_value = expected_response
3730 |
3731 | # Call the method with all parameters
3732 | result = await handler.manage_aws_glue_data_catalog_partitions(
3733 | mock_ctx,
3734 | operation='list-partitions',
3735 | database_name='test-db',
3736 | table_name='test-table',
3737 | max_results=10,
3738 | expression="year='2023'",
3739 | catalog_id='123456789012',
3740 | )
3741 |
3742 | # Verify that the method was called with the correct parameters
3743 | mock_catalog_manager.list_partitions.assert_called_once()
3744 | assert mock_catalog_manager.list_partitions.call_args[1]['database_name'] == 'test-db'
3745 | assert mock_catalog_manager.list_partitions.call_args[1]['table_name'] == 'test-table'
3746 | assert mock_catalog_manager.list_partitions.call_args[1]['max_results'] == 10
3747 | assert mock_catalog_manager.list_partitions.call_args[1]['expression'] == "year='2023'"
3748 | assert mock_catalog_manager.list_partitions.call_args[1]['catalog_id'] == '123456789012'
3749 |
3750 | # Verify that the result is the expected response
3751 | assert result == expected_response
3752 | assert len(result.partitions) == 2
3753 |
3754 | @pytest.mark.asyncio
3755 | async def test_manage_aws_glue_data_catalog_connections_list_with_max_results(
3756 | self, handler, mock_ctx, mock_catalog_manager
3757 | ):
3758 | """Test listing connections with max_results parameter."""
3759 | # Setup the mock to return a response
3760 | expected_response = MagicMock()
3761 | expected_response.isError = False
3762 | expected_response.content = []
3763 | expected_response.connections = [
3764 | {'Name': 'connection1', 'ConnectionType': 'JDBC'},
3765 | {'Name': 'connection2', 'ConnectionType': 'KAFKA'},
3766 | ]
3767 | expected_response.count = 2
3768 | expected_response.operation = 'list-connections'
3769 | mock_catalog_manager.list_connections.return_value = expected_response
3770 |
3771 | # Call the method with max_results
3772 | result = await handler.manage_aws_glue_data_catalog_connections(
3773 | mock_ctx,
3774 | operation='list-connections',
3775 | )
3776 |
3777 | # Verify that the method was called with the correct parameters
3778 | mock_catalog_manager.list_connections.assert_called_once()
3779 |
3780 | # Verify that the result is the expected response
3781 | assert result == expected_response
3782 | assert len(result.connections) == 2
3783 |
3784 | @pytest.mark.asyncio
3785 | async def test_manage_aws_glue_data_catalog_connections_list_with_all_parameters(
3786 | self, handler, mock_ctx, mock_catalog_manager
3787 | ):
3788 | """Test listing connections with all parameters."""
3789 | # Setup the mock to return a response
3790 | expected_response = MagicMock()
3791 | expected_response.isError = False
3792 | expected_response.content = []
3793 | expected_response.connections = [
3794 | {'Name': 'connection1', 'ConnectionType': 'JDBC'},
3795 | {'Name': 'connection2', 'ConnectionType': 'KAFKA'},
3796 | ]
3797 | expected_response.count = 2
3798 | expected_response.next_token = 'next-token-value'
3799 | expected_response.operation = 'list-connections'
3800 | mock_catalog_manager.list_connections.return_value = expected_response
3801 |
3802 | # Call the method with all parameters
3803 | result = await handler.manage_aws_glue_data_catalog_connections(
3804 | mock_ctx,
3805 | operation='list-connections',
3806 | catalog_id='123456789012',
3807 | )
3808 |
3809 | # Verify that the method was called with the correct parameters
3810 | mock_catalog_manager.list_connections.assert_called_once()
3811 | assert mock_catalog_manager.list_connections.call_args[1]['catalog_id'] == '123456789012'
3812 |
3813 | # Verify that the result is the expected response
3814 | assert result == expected_response
3815 | assert len(result.connections) == 2
3816 |
3817 | @pytest.mark.asyncio
3818 | async def test_manage_aws_glue_data_catalog_connections_get_with_all_parameters(
3819 | self, handler, mock_ctx, mock_catalog_manager
3820 | ):
3821 | """Test getting a connection with all parameters."""
3822 | # Setup the mock to return a response
3823 | expected_response = MagicMock()
3824 | expected_response.isError = False
3825 | expected_response.content = []
3826 | expected_response.connection_name = 'test-connection'
3827 | expected_response.connection_type = 'JDBC'
3828 | expected_response.connection_properties = {
3829 | 'JDBC_CONNECTION_URL': 'jdbc:mysql://test-host:3306/test-db'
3830 | }
3831 | expected_response.operation = 'get'
3832 | mock_catalog_manager.get_connection.return_value = expected_response
3833 |
3834 | # Call the method with all parameters
3835 | result = await handler.manage_aws_glue_data_catalog_connections(
3836 | mock_ctx,
3837 | operation='get-connection',
3838 | connection_name='test-connection',
3839 | catalog_id='123456789012',
3840 | )
3841 |
3842 | # Verify that the method was called with the correct parameters
3843 | mock_catalog_manager.get_connection.assert_called_once()
3844 | assert (
3845 | mock_catalog_manager.get_connection.call_args[1]['connection_name']
3846 | == 'test-connection'
3847 | )
3848 | assert mock_catalog_manager.get_connection.call_args[1]['catalog_id'] == '123456789012'
3849 |
3850 | # Verify that the result is the expected response
3851 | assert result == expected_response
3852 |
```